<?php
/**
 * setup_tv.php — Visual Setup Tool untuk TV Baru (Batch Support)
 * 
 * Setup satu atau banyak TV sekaligus via browser.
 * Jalankan SEKALI per TV baru setelah install APK.
 *
 * Usage: http://localhost/escobarweb/setup_tv.php
 */
ob_start();

include 'config.php';
checkLogin();
onlyAdmin();

$page_title  = "TV Setup Wizard";
$active_page = "setup_tv";

// ── Config ────────────────────────────────────────────────────
$adb_path = get_setting($conn, 'adb_path') ?: (__DIR__ . '/adb.exe');
$package  = 'com.example.escobar_tv_client';
$a11y_svc = $package . '/.EscobarAccessibilityService';

// ── Ambil daftar TV dari DB ───────────────────────────────────
$tvs_all = [];
$q = mysqli_query($conn, "SELECT id, nama_tv, ip_address, status FROM tvs ORDER BY nama_tv ASC");
while ($r = mysqli_fetch_assoc($q)) $tvs_all[] = $r;

// ── Handle AJAX setup request ─────────────────────────────────
if (isset($_POST['action']) && $_POST['action'] === 'setup_tv') {
    header('Content-Type: application/json');
    
    $ip = trim($_POST['ip'] ?? '');
    $tv_name = trim($_POST['tv_name'] ?? "TV $ip");
    
    if (empty($ip) || !preg_match('/^[\d\.]+$/', $ip)) {
        echo json_encode(['status' => 'error', 'msg' => 'IP tidak valid']);
        exit;
    }
    
    if (empty($adb_path) || !file_exists($adb_path)) {
        echo json_encode(['status' => 'error', 'msg' => 'ADB path tidak ditemukan: ' . $adb_path]);
        exit;
    }
    
    $s = trim($ip) . ':5555';
    $steps = [];
    $all_ok = true;
    
    // Step 1: Connect
    $out = shell_exec("\"$adb_path\" connect $s 2>&1");
    $steps[] = ['step' => 'ADB Connect', 'output' => trim($out), 'ok' => (strpos($out, 'connected') !== false || strpos($out, 'already') !== false)];
    if (!$steps[0]['ok']) $all_ok = false;
    sleep(1);
    
    // Step 2: Verify
    $devices = shell_exec("\"$adb_path\" devices 2>&1");
    $found = (strpos($devices, $ip) !== false);
    $steps[] = ['step' => 'Verifikasi Koneksi', 'output' => $found ? 'Device terdeteksi' : 'Device tidak ditemukan', 'ok' => $found];
    if (!$found) $all_ok = false;
    
    if ($found) {
        // Step 3: Grant permission
        $out = shell_exec("\"$adb_path\" -s $s shell pm grant $package android.permission.WRITE_SECURE_SETTINGS 2>&1");
        $grant_ok = (empty(trim($out)) || strpos($out, 'Exception') === false);
        $steps[] = ['step' => 'Grant WRITE_SECURE_SETTINGS', 'output' => $grant_ok ? 'Permission granted' : trim($out), 'ok' => $grant_ok];
        sleep(1);
        
        // Step 4: Enable Accessibility (APPEND)
        $current = trim(shell_exec("\"$adb_path\" -s $s shell settings get secure enabled_accessibility_services 2>&1"));
        if ($current === 'null' || empty($current)) $current = '';
        
        if (strpos($current, $a11y_svc) !== false) {
            $steps[] = ['step' => 'Accessibility Service', 'output' => 'Sudah aktif (skip)', 'ok' => true];
        } else {
            $newList = empty($current) ? $a11y_svc : $current . ':' . $a11y_svc;
            $safeList = str_replace(["'", '"', '`', '$', ';', '|', '&', "\n", "\r"], '', $newList);
            shell_exec("\"$adb_path\" -s $s shell settings put secure enabled_accessibility_services '$safeList' 2>&1");
            shell_exec("\"$adb_path\" -s $s shell settings put secure accessibility_enabled 1 2>&1");
            
            // Verify
            $verify = trim(shell_exec("\"$adb_path\" -s $s shell settings get secure enabled_accessibility_services 2>&1"));
            $a11y_ok = (strpos($verify, $a11y_svc) !== false);
            $steps[] = ['step' => 'Accessibility Service', 'output' => $a11y_ok ? 'Berhasil diaktifkan' : 'Gagal verifikasi', 'ok' => $a11y_ok];
        }
        
        // Step 5: Start service
        $out = shell_exec("\"$adb_path\" -s $s shell am start-foreground-service -n $package/.OverlayService 2>&1");
        $svc_ok = (empty(trim($out)) || strpos($out, 'Error') === false);
        $steps[] = ['step' => 'Start Overlay Service', 'output' => $svc_ok ? 'Service started' : trim($out), 'ok' => $svc_ok];
    }
    
    // Log
    $status_text = $all_ok ? 'SUCCESS' : 'PARTIAL';
    write_log($conn, 'SETUP_TV', "$tv_name ($ip) | Status: $status_text | Steps: " . count($steps));
    
    echo json_encode(['status' => 'success', 'steps' => $steps, 'all_ok' => $all_ok]);
    exit;
}

// ── Handle AJAX: Quick check ADB status ───────────────────────
if (isset($_POST['action']) && $_POST['action'] === 'quick_check') {
    header('Content-Type: application/json');
    $ip = trim($_POST['ip'] ?? '');
    if (empty($ip)) { echo json_encode(['online' => false]); exit; }
    
    $adb_list = getADBList();
    $status = checkADBStatus($ip, $adb_list);
    echo json_encode(['online' => ($status === 'online'), 'status' => $status]);
    exit;
}

include 'layout.php';
?>

<link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@400;500;600;700;800;900&family=Plus+Jakarta+Sans:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600;700&display=swap" rel="stylesheet">
<link href='https://unpkg.com/boxicons@2.1.4/css/boxicons.min.css' rel='stylesheet'>

<style>
:root {
    --bg-dark: #030712;
    --card-bg: rgba(15, 23, 42, 0.6);
    --card-border: rgba(6, 182, 212, 0.15);
    --primary: #06b6d4;
    --primary-glow: rgba(6, 182, 212, 0.4);
    --success: #10b981;
    --success-glow: rgba(16, 185, 129, 0.4);
    --warning: #f59e0b;
    --danger: #ef4444;
    --danger-glow: rgba(239, 68, 68, 0.4);
    --text-main: #f1f5f9;
    --text-dim: #64748b;
    --glass-bg: rgba(255, 255, 255, 0.03);
    --glass-border: rgba(255, 255, 255, 0.08);
}

.setup-container { max-width: 1100px; margin: 0 auto; padding: 0 20px 40px; }

/* ── HERO HEADER ── */
.setup-hero {
    text-align: center;
    padding: 40px 20px 30px;
    position: relative;
}
.setup-hero::before {
    content: '';
    position: absolute;
    top: 0; left: 50%;
    transform: translateX(-50%);
    width: 300px; height: 300px;
    background: radial-gradient(circle, var(--primary-glow) 0%, transparent 70%);
    filter: blur(80px);
    opacity: 0.3;
    pointer-events: none;
}
.hero-icon {
    width: 80px; height: 80px;
    background: linear-gradient(135deg, var(--primary), #0891b2);
    border-radius: 24px;
    display: inline-flex; align-items: center; justify-content: center;
    font-size: 2.5rem; color: #fff;
    box-shadow: 0 15px 40px -10px var(--primary-glow);
    margin-bottom: 20px;
    animation: heroFloat 3s ease-in-out infinite;
    position: relative;
}
@keyframes heroFloat { 0%,100% { transform: translateY(0); } 50% { transform: translateY(-8px); } }
.hero-title {
    font-family: 'Orbitron', sans-serif;
    font-size: 1.8rem; font-weight: 800;
    background: linear-gradient(135deg, #fff 0%, var(--primary) 100%);
    -webkit-background-clip: text; -webkit-text-fill-color: transparent;
    margin-bottom: 8px; position: relative;
}
.hero-sub { color: var(--text-dim); font-size: 0.9rem; position: relative; }

/* ── SECTION: ADD CUSTOM IP ── */
.add-section {
    background: var(--card-bg);
    backdrop-filter: blur(20px);
    border: 1px solid var(--card-border);
    border-radius: 20px;
    padding: 24px;
    margin-bottom: 24px;
}
.add-section-title {
    font-size: 0.75rem; font-weight: 800; color: var(--text-dim);
    text-transform: uppercase; letter-spacing: 1px;
    margin-bottom: 14px;
    display: flex; align-items: center; gap: 8px;
}
.add-section-title i { color: var(--primary); font-size: 1rem; }
.add-row { display: flex; gap: 12px; flex-wrap: wrap; }
.add-input {
    flex: 1; min-width: 200px;
    background: rgba(0,0,0,0.3);
    border: 1px solid var(--glass-border);
    padding: 12px 16px; border-radius: 12px;
    color: #fff; font-size: 0.9rem; outline: none;
    transition: border-color 0.3s;
    font-family: 'JetBrains Mono', monospace;
}
.add-input:focus { border-color: var(--primary); }
.add-input::placeholder { color: #334155; }
.btn-add {
    background: linear-gradient(135deg, var(--primary), #0891b2);
    border: none; color: #000; padding: 12px 24px;
    border-radius: 12px; font-weight: 800; cursor: pointer;
    font-size: 0.85rem; display: flex; align-items: center; gap: 8px;
    transition: all 0.3s; white-space: nowrap;
}
.btn-add:hover { transform: translateY(-2px); box-shadow: 0 8px 25px -8px var(--primary-glow); }

/* ── TV GRID ── */
.tv-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
    gap: 20px;
    margin-bottom: 30px;
}

/* ── TV CARD ── */
.tv-setup-card {
    background: var(--card-bg);
    backdrop-filter: blur(20px);
    border: 1px solid var(--card-border);
    border-radius: 20px;
    padding: 24px;
    position: relative;
    overflow: hidden;
    transition: all 0.4s cubic-bezier(0.4,0,0.2,1);
}
.tv-setup-card:hover { transform: translateY(-4px); box-shadow: 0 20px 40px -15px rgba(0,0,0,0.4); }
.tv-setup-card.selected { border-color: var(--primary); box-shadow: 0 0 30px -10px var(--primary-glow); }
.tv-setup-card.selected::after {
    content: ''; position: absolute; top: 0; left: 0; right: 0; height: 3px;
    background: linear-gradient(90deg, var(--primary), #22d3ee);
}
.tv-setup-card.setup-done { border-color: rgba(16,185,129,0.3); }
.tv-setup-card.setup-done::after {
    content: ''; position: absolute; top: 0; left: 0; right: 0; height: 3px;
    background: linear-gradient(90deg, var(--success), #34d399);
}
.tv-setup-card.setup-fail { border-color: rgba(239,68,68,0.3); }
.tv-setup-card.setup-fail::after {
    content: ''; position: absolute; top: 0; left: 0; right: 0; height: 3px;
    background: linear-gradient(90deg, var(--danger), #f87171);
}

.tv-card-header { display: flex; align-items: center; gap: 14px; margin-bottom: 16px; }
.tv-card-icon {
    width: 48px; height: 48px;
    background: linear-gradient(135deg, rgba(6,182,212,0.15), rgba(6,182,212,0.05));
    border: 1px solid rgba(6,182,212,0.2);
    border-radius: 14px;
    display: flex; align-items: center; justify-content: center;
    font-size: 1.4rem; color: var(--primary);
    flex-shrink: 0;
}
.tv-card-name { font-family: 'Orbitron', sans-serif; font-size: 1rem; font-weight: 700; color: #fff; }
.tv-card-ip { font-family: 'JetBrains Mono', monospace; font-size: 0.78rem; color: var(--text-dim); margin-top: 2px; }

.tv-card-checkbox {
    margin-left: auto;
    width: 24px; height: 24px;
    background: rgba(0,0,0,0.3);
    border: 2px solid var(--glass-border);
    border-radius: 8px;
    cursor: pointer;
    display: flex; align-items: center; justify-content: center;
    transition: all 0.3s;
    flex-shrink: 0;
}
.tv-card-checkbox.checked {
    background: var(--primary);
    border-color: var(--primary);
    color: #000;
}
.tv-card-checkbox i { display: none; font-size: 0.9rem; font-weight: 900; }
.tv-card-checkbox.checked i { display: block; }

/* ── STATUS BADGE ── */
.tv-status-row { display: flex; align-items: center; gap: 10px; margin-bottom: 16px; }
.status-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
.status-dot.online { background: var(--success); box-shadow: 0 0 8px var(--success-glow); animation: dotPulse 2s ease-in-out infinite; }
.status-dot.offline { background: var(--danger); box-shadow: 0 0 8px var(--danger-glow); }
.status-dot.checking { background: var(--warning); animation: dotPulse 0.5s ease-in-out infinite; }
@keyframes dotPulse { 0%,100% { transform: scale(1); opacity:1; } 50% { transform: scale(1.4); opacity:0.6; } }
.status-text { font-size: 0.72rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.5px; }
.status-text.online { color: var(--success); }
.status-text.offline { color: var(--danger); }
.status-text.checking { color: var(--warning); }

/* ── SETUP LOG ── */
.setup-log {
    background: rgba(0,0,0,0.3);
    border: 1px solid var(--glass-border);
    border-radius: 14px;
    padding: 14px;
    max-height: 200px;
    overflow-y: auto;
    display: none;
}
.setup-log.show { display: block; }
.log-line {
    display: flex; align-items: flex-start; gap: 10px;
    padding: 8px 0;
    border-bottom: 1px solid rgba(255,255,255,0.03);
    font-size: 0.78rem;
    animation: logSlideIn 0.3s ease;
}
.log-line:last-child { border-bottom: none; }
@keyframes logSlideIn { from { opacity:0; transform:translateX(-10px); } to { opacity:1; transform:translateX(0); } }
.log-icon { width: 20px; height: 20px; border-radius: 6px; display: flex; align-items: center; justify-content: center; font-size: 0.7rem; flex-shrink: 0; margin-top: 1px; }
.log-icon.ok { background: rgba(16,185,129,0.15); color: var(--success); }
.log-icon.fail { background: rgba(239,68,68,0.15); color: var(--danger); }
.log-icon.loading { background: rgba(6,182,212,0.15); color: var(--primary); }
.log-step { color: #fff; font-weight: 700; min-width: 0; }
.log-detail { color: var(--text-dim); font-family: 'JetBrains Mono', monospace; font-size: 0.7rem; word-break: break-all; }

/* ── PROGRESS BAR ── */
.progress-bar {
    height: 4px;
    background: rgba(255,255,255,0.05);
    border-radius: 2px;
    overflow: hidden;
    margin-bottom: 14px;
    display: none;
}
.progress-bar.show { display: block; }
.progress-fill {
    height: 100%;
    background: linear-gradient(90deg, var(--primary), #22d3ee);
    border-radius: 2px;
    width: 0%;
    transition: width 0.5s ease;
}
.progress-fill.done-ok { background: linear-gradient(90deg, var(--success), #34d399); width: 100% !important; }
.progress-fill.done-fail { background: linear-gradient(90deg, var(--danger), #f87171); width: 100% !important; }

/* ── BOTTOM ACTION BAR ── */
.action-bar {
    background: var(--card-bg);
    backdrop-filter: blur(20px);
    border: 1px solid var(--card-border);
    border-radius: 20px;
    padding: 20px 24px;
    display: flex; align-items: center; gap: 16px;
    flex-wrap: wrap;
    position: sticky; bottom: 20px;
    z-index: 100;
    box-shadow: 0 -10px 40px -10px rgba(0,0,0,0.5);
}
.selected-count {
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.85rem; font-weight: 700;
    color: var(--primary);
    display: flex; align-items: center; gap: 8px;
}
.selected-count .count-num {
    background: rgba(6,182,212,0.15);
    padding: 4px 12px; border-radius: 8px;
    min-width: 30px; text-align: center;
}
.btn-setup-all {
    background: linear-gradient(135deg, var(--success), #059669);
    border: none; color: #fff; padding: 14px 28px;
    border-radius: 14px; font-weight: 800; cursor: pointer;
    font-size: 0.9rem; display: flex; align-items: center; gap: 10px;
    transition: all 0.3s; margin-left: auto;
}
.btn-setup-all:hover { transform: translateY(-2px); box-shadow: 0 10px 30px -10px var(--success-glow); }
.btn-setup-all:disabled { opacity: 0.4; cursor: not-allowed; transform: none; box-shadow: none; }
.btn-select-all {
    background: rgba(255,255,255,0.05);
    border: 1px solid var(--glass-border);
    color: var(--text-dim); padding: 12px 20px;
    border-radius: 12px; font-weight: 700; cursor: pointer;
    font-size: 0.8rem; transition: all 0.3s;
}
.btn-select-all:hover { border-color: var(--primary); color: var(--primary); }
.btn-check-all {
    background: rgba(6,182,212,0.1);
    border: 1px solid rgba(6,182,212,0.25);
    color: var(--primary); padding: 12px 20px;
    border-radius: 12px; font-weight: 700; cursor: pointer;
    font-size: 0.8rem; transition: all 0.3s;
    display: flex; align-items: center; gap: 8px;
}
.btn-check-all:hover { background: rgba(6,182,212,0.2); border-color: var(--primary); }

/* ── RESULT BADGE ── */
.result-badge {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 6px 14px; border-radius: 10px;
    font-size: 0.75rem; font-weight: 800;
    text-transform: uppercase; letter-spacing: 0.5px;
}
.result-badge.ok { background: rgba(16,185,129,0.15); color: var(--success); border: 1px solid rgba(16,185,129,0.3); }
.result-badge.fail { background: rgba(239,68,68,0.15); color: var(--danger); border: 1px solid rgba(239,68,68,0.3); }
.result-badge.running { background: rgba(6,182,212,0.15); color: var(--primary); border: 1px solid rgba(6,182,212,0.3); }

/* ── CUSTOM TV CARD (added via input) ── */
.tv-setup-card.custom-card { border-style: dashed; }

/* ── RESPONSIVE ── */
@media (max-width: 768px) {
    .tv-grid { grid-template-columns: 1fr; }
    .action-bar { flex-direction: column; text-align: center; }
    .btn-setup-all { margin-left: 0; width: 100%; justify-content: center; }
}

::-webkit-scrollbar { width: 6px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: rgba(6,182,212,0.3); border-radius: 3px; }
</style>

<div class="setup-container">

    <!-- ── HERO ── -->
    <div class="setup-hero">
        <div class="hero-icon"><i class='bx bx-chip'></i></div>
        <div class="hero-title">TV SETUP WIZARD</div>
        <div class="hero-sub">Setup ADB, Accessibility & Service untuk satu atau banyak TV sekaligus</div>
    </div>

    <!-- ── ADD CUSTOM IP ── -->
    <div class="add-section">
        <div class="add-section-title"><i class='bx bx-plus-circle'></i> Tambah TV Manual (IP tidak ada di database)</div>
        <div class="add-row">
            <input type="text" class="add-input" id="custom_ip" placeholder="192.168.1.xxx" style="max-width:220px;">
            <input type="text" class="add-input" id="custom_name" placeholder="Nama TV (opsional)" style="max-width:220px;">
            <button class="btn-add" onclick="addCustomTV()"><i class='bx bx-plus'></i> Tambah ke List</button>
        </div>
    </div>

    <!-- ── TV GRID ── -->
    <div class="tv-grid" id="tvGrid">
        <?php foreach ($tvs_all as $tv): ?>
        <div class="tv-setup-card" id="card-<?= $tv['id'] ?>" data-ip="<?= htmlspecialchars($tv['ip_address']) ?>" data-name="<?= htmlspecialchars($tv['nama_tv']) ?>">
            <div class="tv-card-header">
                <div class="tv-card-icon"><i class='bx bx-tv'></i></div>
                <div>
                    <div class="tv-card-name"><?= htmlspecialchars($tv['nama_tv']) ?></div>
                    <div class="tv-card-ip"><?= htmlspecialchars($tv['ip_address']) ?></div>
                </div>
                <div class="tv-card-checkbox" onclick="toggleSelect(this)">
                    <i class='bx bx-check'></i>
                </div>
            </div>

            <div class="tv-status-row">
                <div class="status-dot offline" id="dot-<?= $tv['id'] ?>"></div>
                <span class="status-text offline" id="stxt-<?= $tv['id'] ?>">Belum dicek</span>
            </div>

            <div class="progress-bar" id="prog-<?= $tv['id'] ?>">
                <div class="progress-fill" id="progfill-<?= $tv['id'] ?>"></div>
            </div>

            <div class="setup-log" id="log-<?= $tv['id'] ?>"></div>
        </div>
        <?php endforeach; ?>
    </div>

    <!-- ── ACTION BAR ── -->
    <div class="action-bar">
        <div class="selected-count">
            <i class='bx bx-check-square' style="font-size:1.2rem;"></i>
            <span class="count-num" id="selectedCount">0</span> TV dipilih
        </div>
        <button class="btn-select-all" onclick="selectAll()">
            <i class='bx bx-select-multiple'></i> Pilih Semua
        </button>
        <button class="btn-check-all" onclick="checkAllStatus()">
            <i class='bx bx-wifi'></i> Cek Status ADB
        </button>
        <button class="btn-setup-all" id="btnSetupAll" onclick="setupSelected()" disabled>
            <i class='bx bx-rocket'></i> SETUP TV TERPILIH
        </button>
    </div>

</div>

<script>
let customCounter = 0;
let isRunning = false;

// ══════════════════════════════════════════
// SELECTION
// ══════════════════════════════════════════
function toggleSelect(el) {
    if (isRunning) return;
    el.classList.toggle('checked');
    el.closest('.tv-setup-card').classList.toggle('selected');
    updateCount();
}

function selectAll() {
    if (isRunning) return;
    const cards = document.querySelectorAll('.tv-setup-card');
    const boxes = document.querySelectorAll('.tv-card-checkbox');
    const allSelected = document.querySelectorAll('.tv-card-checkbox.checked').length === boxes.length;
    
    boxes.forEach(b => {
        if (allSelected) { b.classList.remove('checked'); b.closest('.tv-setup-card').classList.remove('selected'); }
        else { b.classList.add('checked'); b.closest('.tv-setup-card').classList.add('selected'); }
    });
    updateCount();
}

function updateCount() {
    const count = document.querySelectorAll('.tv-card-checkbox.checked').length;
    document.getElementById('selectedCount').textContent = count;
    document.getElementById('btnSetupAll').disabled = (count === 0);
}

// ══════════════════════════════════════════
// ADD CUSTOM TV
// ══════════════════════════════════════════
function addCustomTV() {
    const ip = document.getElementById('custom_ip').value.trim();
    const name = document.getElementById('custom_name').value.trim() || `Custom TV`;
    
    if (!ip || !/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(ip)) {
        Swal.fire({ title: 'IP Tidak Valid', text: 'Masukkan format IP yang benar (contoh: 192.168.1.100)', icon: 'warning', background: '#1e293b', color: '#fff' });
        return;
    }
    
    // Check duplicate
    const existing = document.querySelectorAll('.tv-setup-card');
    for (const c of existing) {
        if (c.dataset.ip === ip) {
            Swal.fire({ title: 'IP Sudah Ada', text: `${ip} sudah ada di daftar.`, icon: 'info', background: '#1e293b', color: '#fff' });
            return;
        }
    }
    
    customCounter++;
    const cid = `custom-${customCounter}`;
    
    const html = `
    <div class="tv-setup-card custom-card selected" id="card-${cid}" data-ip="${ip}" data-name="${name}">
        <div class="tv-card-header">
            <div class="tv-card-icon" style="border-color:rgba(168,85,247,0.3);background:rgba(168,85,247,0.1);color:#a855f7;">
                <i class='bx bx-plus-medical'></i>
            </div>
            <div>
                <div class="tv-card-name">${name}</div>
                <div class="tv-card-ip">${ip}</div>
            </div>
            <div class="tv-card-checkbox checked" onclick="toggleSelect(this)">
                <i class='bx bx-check'></i>
            </div>
        </div>
        <div class="tv-status-row">
            <div class="status-dot offline" id="dot-${cid}"></div>
            <span class="status-text offline" id="stxt-${cid}">Belum dicek</span>
        </div>
        <div class="progress-bar" id="prog-${cid}">
            <div class="progress-fill" id="progfill-${cid}"></div>
        </div>
        <div class="setup-log" id="log-${cid}"></div>
    </div>`;
    
    document.getElementById('tvGrid').insertAdjacentHTML('beforeend', html);
    document.getElementById('custom_ip').value = '';
    document.getElementById('custom_name').value = '';
    updateCount();
}

// ══════════════════════════════════════════
// CHECK ADB STATUS
// ══════════════════════════════════════════
async function checkAllStatus() {
    const cards = document.querySelectorAll('.tv-setup-card');
    for (const card of cards) {
        const ip = card.dataset.ip;
        const id = card.id.replace('card-', '');
        const dot = document.getElementById(`dot-${id}`);
        const stxt = document.getElementById(`stxt-${id}`);
        
        if (!ip) continue;
        
        dot.className = 'status-dot checking';
        stxt.className = 'status-text checking';
        stxt.textContent = 'Mengecek...';
        
        try {
            const fd = new FormData();
            fd.append('action', 'quick_check');
            fd.append('ip', ip);
            const resp = await fetch('setup_tv.php', { method: 'POST', body: fd });
            const data = await resp.json();
            
            if (data.online) {
                dot.className = 'status-dot online';
                stxt.className = 'status-text online';
                stxt.textContent = 'ADB Online';
            } else {
                dot.className = 'status-dot offline';
                stxt.className = 'status-text offline';
                stxt.textContent = 'ADB Offline';
            }
        } catch {
            dot.className = 'status-dot offline';
            stxt.className = 'status-text offline';
            stxt.textContent = 'Error';
        }
    }
}

// ══════════════════════════════════════════
// SETUP SELECTED TVs (sequential)
// ══════════════════════════════════════════
async function setupSelected() {
    const selected = document.querySelectorAll('.tv-card-checkbox.checked');
    if (selected.length === 0) return;
    
    isRunning = true;
    document.getElementById('btnSetupAll').disabled = true;
    document.getElementById('btnSetupAll').innerHTML = '<i class="bx bx-loader-alt bx-spin"></i> SEDANG SETUP...';
    
    let doneOk = 0, doneFail = 0;
    
    for (const checkbox of selected) {
        const card = checkbox.closest('.tv-setup-card');
        const id = card.id.replace('card-', '');
        const ip = card.dataset.ip;
        const name = card.dataset.name;
        
        const progBar = document.getElementById(`prog-${id}`);
        const progFill = document.getElementById(`progfill-${id}`);
        const logBox = document.getElementById(`log-${id}`);
        const dot = document.getElementById(`dot-${id}`);
        const stxt = document.getElementById(`stxt-${id}`);
        
        // Reset
        progBar.classList.add('show');
        logBox.classList.add('show');
        logBox.innerHTML = '';
        progFill.className = 'progress-fill';
        progFill.style.width = '10%';
        card.classList.remove('setup-done', 'setup-fail');
        
        dot.className = 'status-dot checking';
        stxt.className = 'status-text checking';
        stxt.textContent = 'Setting up...';
        
        addLog(logBox, 'loading', 'Memulai setup...', `IP: ${ip}`);
        
        // Scroll card into view
        card.scrollIntoView({ behavior: 'smooth', block: 'center' });
        
        try {
            progFill.style.width = '30%';
            
            const fd = new FormData();
            fd.append('action', 'setup_tv');
            fd.append('ip', ip);
            fd.append('tv_name', name);
            
            const resp = await fetch('setup_tv.php', { method: 'POST', body: fd });
            const data = await resp.json();
            
            progFill.style.width = '80%';
            
            if (data.status === 'success' && data.steps) {
                data.steps.forEach(s => {
                    addLog(logBox, s.ok ? 'ok' : 'fail', s.step, s.output);
                });
                
                if (data.all_ok) {
                    progFill.classList.add('done-ok');
                    card.classList.add('setup-done');
                    dot.className = 'status-dot online';
                    stxt.className = 'status-text online';
                    stxt.textContent = 'Setup OK';
                    addLog(logBox, 'ok', 'SETUP BERHASIL', 'TV siap digunakan');
                    doneOk++;
                } else {
                    progFill.classList.add('done-fail');
                    card.classList.add('setup-fail');
                    dot.className = 'status-dot offline';
                    stxt.className = 'status-text offline';
                    stxt.textContent = 'Partial fail';
                    addLog(logBox, 'fail', 'SETUP PARTIAL', 'Beberapa step gagal');
                    doneFail++;
                }
            } else {
                progFill.classList.add('done-fail');
                card.classList.add('setup-fail');
                dot.className = 'status-dot offline';
                stxt.className = 'status-text offline';
                stxt.textContent = 'Error';
                addLog(logBox, 'fail', 'ERROR', data.msg || 'Gagal setup');
                doneFail++;
            }
        } catch (err) {
            progFill.classList.add('done-fail');
            card.classList.add('setup-fail');
            dot.className = 'status-dot offline';
            stxt.className = 'status-text offline';
            stxt.textContent = 'Network error';
            addLog(logBox, 'fail', 'NETWORK ERROR', err.message);
            doneFail++;
        }
        
        // Small delay between TVs
        await new Promise(r => setTimeout(r, 500));
    }
    
    isRunning = false;
    document.getElementById('btnSetupAll').disabled = false;
    document.getElementById('btnSetupAll').innerHTML = '<i class="bx bx-rocket"></i> SETUP TV TERPILIH';
    
    // Summary
    Swal.fire({
        title: doneOk > 0 ? '✅ Setup Selesai' : '⚠ Setup Gagal',
        html: `<div style="text-align:center;color:#94a3b8;font-size:.9rem;line-height:2;">
            <div style="display:flex;justify-content:center;gap:30px;margin:16px 0;">
                <div><div style="font-size:2rem;font-weight:900;color:#10b981;">${doneOk}</div><div style="font-size:.75rem;">Berhasil</div></div>
                <div><div style="font-size:2rem;font-weight:900;color:#ef4444;">${doneFail}</div><div style="font-size:.75rem;">Gagal</div></div>
            </div>
        </div>`,
        icon: null,
        confirmButtonText: 'OK',
        confirmButtonColor: '#06b6d4',
        background: '#1e293b',
        color: '#fff',
    });
}

function addLog(container, type, step, detail) {
    const iconClass = type === 'ok' ? 'ok' : type === 'fail' ? 'fail' : 'loading';
    const iconHtml = type === 'ok' ? '<i class="bx bx-check"></i>' : type === 'fail' ? '<i class="bx bx-x"></i>' : '<i class="bx bx-loader-alt bx-spin"></i>';
    
    container.insertAdjacentHTML('beforeend', `
        <div class="log-line">
            <div class="log-icon ${iconClass}">${iconHtml}</div>
            <div>
                <div class="log-step">${step}</div>
                <div class="log-detail">${detail}</div>
            </div>
        </div>
    `);
    container.scrollTop = container.scrollHeight;
}

// Auto check status on load
setTimeout(checkAllStatus, 1000);
</script>

<?php
echo "</div></body></html>";
ob_end_flush();
?>