<?php
// ==========================================================
// PROCESS.PHP
// Fix sinkronisasi timer: 'seconds' selalu dihitung dari
// target_selesai yang tersimpan di DB (bukan durasi_detik mentah)
// sehingga delay wake/INSERT/ADB tidak menyebabkan timer meleset.
// Fix pause/resume open bill: seconds=0 + start_timestamp
// Fix add_time saat paused: hanya update DB, tidak kirim overlay
// ==========================================================
ob_start();

include 'config.php';
checkLogin();

$action   = $_REQUEST['action'] ?? '';
$tv_id    = isset($_REQUEST['tv_id']) ? (int)$_REQUEST['tv_id'] : null;
$redirect = "Location: index.php";

$ip = ""; $trx_id = null; $nama_tv = "";
if ($tv_id) {
    $tv_data_global = getTVData($conn, $tv_id);
    if ($tv_data_global) {
        $ip      = $tv_data_global['ip_address'];
        $trx_id  = $tv_data_global['current_trx_id'];
        $nama_tv = $tv_data_global['nama_tv'];
    }
}

$rental_name = get_setting($conn, 'app_name');

// Ambil semua overlay settings sekali di awal request
$ov = getOverlaySettings($conn);

function getCustomerName($conn, $trx_id) {
    if (!$trx_id) return 'Tamu';
    $s = $conn->prepare("SELECT m.nama_member FROM transactions t LEFT JOIN members m ON t.member_id = m.id WHERE t.id = ? LIMIT 1");
    $s->bind_param("i", $trx_id); $s->execute();
    $r    = $s->get_result()->fetch_assoc(); $s->close();
    $nama = $r['nama_member'] ?? '';
    return (!empty($nama)) ? $nama : 'Tamu';
}

switch ($action) {

    // --- AMBIL RINGKASAN BIAYA ---
    case 'get_summary':
        if (ob_get_length()) ob_clean();
        header('Content-Type: application/json');
        try {
            $trx_id = isset($_REQUEST['trx_id']) ? (int)$_REQUEST['trx_id'] : null;
            if (!$trx_id) {
                $stmt_tv = $conn->prepare("SELECT current_trx_id FROM tvs WHERE id=?");
                $stmt_tv->bind_param("i", $tv_id); $stmt_tv->execute();
                $tv_row = $stmt_tv->get_result()->fetch_assoc(); $stmt_tv->close();
                $trx_id = $tv_row['current_trx_id'] ?? null;
            }
            if (!$trx_id) throw new Exception("Tidak ada transaksi aktif");
            $stmt = $conn->prepare("SELECT t.*, p.nama_paket, m.nama_member FROM transactions t LEFT JOIN packages p ON t.paket_id = p.id LEFT JOIN members m ON t.member_id = m.id WHERE t.id = ?");
            $stmt->bind_param("i", $trx_id); $stmt->execute();
            $trx = $stmt->get_result()->fetch_assoc(); $stmt->close();
            if (!$trx) throw new Exception("Data transaksi tidak ditemukan");
            if ($trx['status'] == 'completed' && !empty($trx['end_time'])) {
                $durasi = max(0, strtotime($trx['end_time']) - strtotime($trx['start_time']));
            } else {
                $durasi = max(0, time() - strtotime($trx['start_time']));
            }
            $biaya     = (int)$trx['total_bayar'];
            $calc_info = null;
            if ($trx['jenis_paket'] == 'open') {
                $r            = (int)$trx['rate_per_jam'];
                $min          = (int)get_setting($conn, 'min_open_bill');
                $ro           = (int)get_setting($conn, 'round_open_bill') ?: 100;
                $biaya_mentah = ($durasi / 3600) * $r;
                $biaya        = max($min, ceil($biaya_mentah / $ro) * $ro);
                $calc_info    = ['rate_per_jam' => $r, 'biaya_mentah' => (int)$biaya_mentah, 'min_charge' => $min, 'round_to' => $ro];
            }
            $stmtf = $conn->prepare("SELECT nama_barang, qty, total_harga FROM orders_fnb WHERE trx_id = ? ORDER BY created_at ASC");
            $stmtf->bind_param("i", $trx_id); $stmtf->execute();
            $fnb_res  = $stmtf->get_result();
            $fnb_list = []; $fnb_total = 0;
            while ($fnb_row = $fnb_res->fetch_assoc()) {
                $fnb_list[] = ['nama_barang' => $fnb_row['nama_barang'], 'qty' => (int)$fnb_row['qty'], 'total_harga' => (int)$fnb_row['total_harga']];
                $fnb_total += (int)$fnb_row['total_harga'];
            }
            $stmtf->close();
            $d_jam    = floor($durasi/3600); $d_menit = floor(($durasi%3600)/60); $d_detik = $durasi%60;
            $durasi_str = $d_jam > 0 ? "{$d_jam}j {$d_menit}m {$d_detik}d" : "{$d_menit}m {$d_detik}d";
            echo json_encode([
                'status' => 'success', 'player' => $trx['nama_member'] ?? 'Tamu',
                'paket' => $trx['jenis_paket'], 'jenis_paket' => $trx['jenis_paket'],
                'biaya_sesi' => $biaya, 'fnb_total' => $fnb_total, 'fnb_list' => $fnb_list,
                'grand_total' => $biaya + $fnb_total, 'durasi' => $durasi_str, 'calc_info' => $calc_info
            ]);
        } catch (Exception $e) { echo json_encode(['status' => 'error', 'msg' => $e->getMessage()]); }
        exit;

    // --- ORDER FNB ---
    case 'order_fnb':
        if (!$tv_id) { header("Location: index.php?status=error"); exit; }
        $snack_id = (int)$_POST['snack_id']; $qty = (int)$_POST['qty'];
        if ($qty < 1) { header("Location: index.php?status=invalid_qty"); exit; }
        $stmt_tv = $conn->prepare("SELECT current_trx_id FROM tvs WHERE id=?");
        $stmt_tv->bind_param("i", $tv_id); $stmt_tv->execute();
        $tv_row = $stmt_tv->get_result()->fetch_assoc(); $stmt_tv->close();
        $trx_id = $tv_row['current_trx_id'] ?? null;
        if (!$trx_id) { header("Location: index.php?status=no_active_session"); exit; }
        $stmt_s = $conn->prepare("SELECT * FROM snacks WHERE id=? AND stok >= ?");
        $stmt_s->bind_param("ii", $snack_id, $qty); $stmt_s->execute();
        $snack = $stmt_s->get_result()->fetch_assoc(); $stmt_s->close();
        if (!$snack) { header("Location: index.php?status=stok_tidak_cukup"); exit; }
        $nama_barang = $snack['nama_barang']; $harga_jual = (int)$snack['harga_jual']; $total_harga = $harga_jual * $qty;
        $stmt_o = $conn->prepare("INSERT INTO orders_fnb (trx_id, tv_id, nama_barang, qty, harga_jual, total_harga, created_at) VALUES (?, ?, ?, ?, ?, ?, NOW())");
        $stmt_o->bind_param("iisiii", $trx_id, $tv_id, $nama_barang, $qty, $harga_jual, $total_harga);
        if ($stmt_o->execute()) {
            $conn->query("UPDATE snacks SET stok = stok - $qty WHERE id = $snack_id");
            write_log($conn, 'ORDER_FNB', "TV $tv_id order {$nama_barang} x$qty = Rp ".number_format($total_harga));
        }
        $stmt_o->close();
        break;

    // --- TAMBAH WAKTU ---
    case 'add_time':
        if (ob_get_length()) ob_clean(); header('Content-Type: application/json');
        try {
            if (!$tv_id || !$trx_id) throw new Exception("Tidak ada sesi aktif");
            $paket_id = (int)($_POST['paket_id'] ?? 0);
            if (!$paket_id) throw new Exception("Paket tidak valid");
            $stmt_p = $conn->prepare("SELECT * FROM packages WHERE id = ?");
            $stmt_p->bind_param("i", $paket_id); $stmt_p->execute();
            $pkt = $stmt_p->get_result()->fetch_assoc(); $stmt_p->close();
            if (!$pkt) throw new Exception("Paket tidak ditemukan");
            $stmt_t = $conn->prepare("SELECT * FROM transactions WHERE id = ? AND jenis_paket = 'fixed'");
            $stmt_t->bind_param("i", $trx_id); $stmt_t->execute();
            $trx = $stmt_t->get_result()->fetch_assoc(); $stmt_t->close();
            if (!$trx) throw new Exception("Transaksi fixed tidak ditemukan");
            $tambah_menit = (int)$pkt['durasi_menit']; $tambah_harga = (int)$pkt['harga'];
if ($trx['status'] === 'paused') {
    $base_sisa  = max(0, (int)$trx['remaining_seconds']);
    $new_target = date('Y-m-d H:i:s', time() + $base_sisa + ($tambah_menit * 60));
} else {
    $target_ts  = strtotime($trx['target_selesai']); $now = time();
    $new_target = date('Y-m-d H:i:s', ($target_ts < $now ? $now : $target_ts) + ($tambah_menit * 60));
}


            $new_bayar    = (int)$trx['total_bayar'] + $tambah_harga;
            $stmt_u = $conn->prepare("UPDATE transactions SET target_selesai = ?, total_bayar = ? WHERE id = ?");
            $stmt_u->bind_param("sii", $new_target, $new_bayar, $trx_id); $stmt_u->execute(); $stmt_u->close();

            // Baca dari DB setelah UPDATE agar tidak ada selisih detik
$stmt_tgt = $conn->prepare("SELECT UNIX_TIMESTAMP(target_selesai) as target_unix FROM transactions WHERE id = ?");
$stmt_tgt->bind_param("i", $trx_id); $stmt_tgt->execute();
$tgt_row        = $stmt_tgt->get_result()->fetch_assoc(); $stmt_tgt->close();
$new_sisa_detik = max(1, (int)$tgt_row['target_unix'] - time());

            // ── FIX: Jika status PAUSED, jangan kirim overlay ke TV ──────
            // Hanya update remaining_seconds di DB agar saat resume
            // waktu yang dipakai sudah termasuk tambahan.
            if ($trx['status'] === 'paused') {
                $stmt_rem = $conn->prepare("UPDATE transactions SET remaining_seconds = ? WHERE id = ?");
                $stmt_rem->bind_param("ii", $new_sisa_detik, $trx_id);
                $stmt_rem->execute(); $stmt_rem->close();
                // TV tetap PAUSE, tidak kirim overlay ke Android
            } else {
                $conn->query("UPDATE tvs SET status='active' WHERE id=$tv_id");
                $customer_name = getCustomerName($conn, $trx_id);
                controlTV($ip, 'start_overlay', array_merge([
                    'action'   => 'TIMER',
                    'seconds'  => $new_sisa_detik,
                    'minutes'  => 0,
                    'customer' => $customer_name,
                    'rental'   => $rental_name,
                    'tv_no'    => $nama_tv,
                ], $ov));
            }

            write_log($conn, 'ADD_TIME', "TV $tv_id tambah: {$pkt['nama_paket']} (+{$tambah_menit}m) | Status: {$trx['status']}");
            echo json_encode([
                'status'          => 'success',
                'msg'             => "Berhasil tambah {$tambah_menit} menit",
                'new_sisa_detik'  => $new_sisa_detik,
                'new_total_bayar' => $new_bayar,
                'tambah_menit'    => $tambah_menit,
                'tambah_harga'    => $tambah_harga,
                'nama_paket'      => $pkt['nama_paket'],
                'is_paused'       => ($trx['status'] === 'paused'),
            ]);
        } catch (Exception $e) { echo json_encode(['status'=>'error','msg'=>$e->getMessage()]); }
        exit;

    // --- START SESSION FIXED ---
    case 'start':
        $paket_id  = (int)$_POST['paket_id'];
        $member_id = !empty($_POST['member_id']) ? (int)$_POST['member_id'] : null;
        $stik      = !empty($_POST['stik']) ? implode(", ", $_POST['stik']) : "Tanpa Stik";
        $stmt_p = $conn->prepare("SELECT * FROM packages WHERE id = ?");
        $stmt_p->bind_param("i", $paket_id); $stmt_p->execute();
        $pkt = $stmt_p->get_result()->fetch_assoc(); $stmt_p->close();
        $customer_name = 'Tamu';
        if ($member_id) {
            $stmt_m = $conn->prepare("SELECT nama_member FROM members WHERE id = ? LIMIT 1");
            $stmt_m->bind_param("i", $member_id); $stmt_m->execute();
            $mr = $stmt_m->get_result()->fetch_assoc(); $stmt_m->close();
            if ($mr && !empty($mr['nama_member'])) $customer_name = $mr['nama_member'];
        }

        $durasi_detik = (int)$pkt['durasi_menit'] * 60;

        // Wake dulu (non-blocking sekarang jadi tidak delay)
        controlTV($ip, 'wake');

        // Simpan ke DB
        $stmt = $conn->prepare("INSERT INTO transactions (tv_id, member_id, paket_id, start_time, target_selesai, total_bayar, status, jenis_paket, stik_info) VALUES (?, ?, ?, NOW(), DATE_ADD(NOW(), INTERVAL ? SECOND), ?, 'ongoing', 'fixed', ?)");
        $stmt->bind_param("iiiiis", $tv_id, $member_id, $paket_id, $durasi_detik, $pkt['harga'], $stik);
        if ($stmt->execute()) {
            $new_trx_id = $stmt->insert_id;
            $conn->query("UPDATE tvs SET status='active', current_trx_id={$new_trx_id} WHERE id=$tv_id");

            // ── FIX UTAMA: Baca target_selesai dari DB setelah INSERT ──
            $stmt_tgt = $conn->prepare("SELECT UNIX_TIMESTAMP(target_selesai) as target_unix FROM transactions WHERE id = ?");
            $stmt_tgt->bind_param("i", $new_trx_id); $stmt_tgt->execute();
            $tgt_row      = $stmt_tgt->get_result()->fetch_assoc(); $stmt_tgt->close();
            $sisa_detik   = max(1, (int)$tgt_row['target_unix'] - time());

            controlTV($ip, 'start_overlay', array_merge([
                'action'   => 'TIMER',
                'seconds'  => $sisa_detik,
                'minutes'  => 0,
                'customer' => $customer_name,
                'rental'   => $rental_name,
                'tv_no'    => $nama_tv,
            ], $ov));
            write_log($conn, 'START_SESSION', "$nama_tv | Paket: {$pkt['nama_paket']} ({$pkt['durasi_menit']}m) | Harga: Rp ".number_format($pkt['harga'])." | Stik: $stik | Customer: $customer_name");
        }
        break;

    // --- START OPEN BILL ---
    case 'start_bebas':
        $rate      = (int)$_POST['harga_per_jam'];
        $stik      = !empty($_POST['stik']) ? implode(", ", $_POST['stik']) : "Tanpa Stik";
        $member_id = !empty($_POST['member_id']) ? (int)$_POST['member_id'] : null;
        $customer_name = 'Tamu';
        if ($member_id) {
            $stmt_m = $conn->prepare("SELECT nama_member FROM members WHERE id = ? LIMIT 1");
            $stmt_m->bind_param("i", $member_id); $stmt_m->execute();
            $mr = $stmt_m->get_result()->fetch_assoc(); $stmt_m->close();
            if ($mr && !empty($mr['nama_member'])) $customer_name = $mr['nama_member'];
        }
        controlTV($ip, 'wake');
        $stmt = $conn->prepare("INSERT INTO transactions (tv_id, member_id, start_time, total_bayar, status, jenis_paket, rate_per_jam, stik_info) VALUES (?, ?, NOW(), 0, 'ongoing', 'open', ?, ?)");
        $stmt->bind_param("iiis", $tv_id, $member_id, $rate, $stik);
        if ($stmt->execute()) {
            $new_trx_id = $stmt->insert_id;
            $conn->query("UPDATE tvs SET status='active', current_trx_id={$new_trx_id} WHERE id=$tv_id");

            // FIX: Baca UNIX_TIMESTAMP start_time dari DB setelah INSERT
            $stmt_st = $conn->prepare("SELECT UNIX_TIMESTAMP(start_time) as start_unix FROM transactions WHERE id = ?");
            $stmt_st->bind_param("i", $new_trx_id); $stmt_st->execute();
            $st_row     = $stmt_st->get_result()->fetch_assoc(); $stmt_st->close();
            $start_unix = (int)$st_row['start_unix'];

            controlTV($ip, 'start_overlay', array_merge([
                'action'          => 'TIMER',
                'seconds'         => 0,
                'minutes'         => 0,
                'start_timestamp' => $start_unix,
                'customer'        => $customer_name,
                'rental'          => $rental_name,
                'tv_no'           => $nama_tv,
            ], $ov));
            write_log($conn, 'START_OPEN', "$nama_tv | Open Bill | Rate: Rp ".number_format($rate)."/jam | Customer: $customer_name | start_unix=$start_unix");
        }
        break;

    // =====================================================================
    // PAUSE — simpan sisa detik ke DB, kirim PAUSE ke Android
    // =====================================================================
    case 'pause':
        if ($trx_id) {
            $stmt_pg = $conn->prepare("SELECT id, status, jenis_paket, start_time, target_selesai, remaining_seconds FROM transactions WHERE id = ?");
            $stmt_pg->bind_param("i", $trx_id); $stmt_pg->execute();
            $pause_trx = $stmt_pg->get_result()->fetch_assoc(); $stmt_pg->close();

            if ($pause_trx && $pause_trx['status'] === 'ongoing') {
                if ($pause_trx['jenis_paket'] == 'fixed') {
                    $remaining = max(1, strtotime($pause_trx['target_selesai']) - time());
                } else {
                    $remaining = max(1, time() - strtotime($pause_trx['start_time']));
                }
                $stmt_pu = $conn->prepare("UPDATE transactions SET status = 'paused', remaining_seconds = ? WHERE id = ?");
                $stmt_pu->bind_param("ii", $remaining, $trx_id); $stmt_pu->execute(); $stmt_pu->close();
                $stmt_tv = $conn->prepare("UPDATE tvs SET status = 'paused' WHERE id = ?");
                $stmt_tv->bind_param("i", $tv_id); $stmt_tv->execute(); $stmt_tv->close();
                controlTV($ip, 'pause_overlay');
                write_log($conn, 'PAUSE', "$nama_tv | Trx #$trx_id | Sisa: {$remaining}d | Tipe: {$pause_trx['jenis_paket']}");
            }
        }
        if (isset($_REQUEST['ajax'])) {
            if (ob_get_length()) ob_clean();
            header('Content-Type: application/json');
            echo json_encode(['status' => 'success']);
            exit;
        }
        break;

    // =====================================================================
    // RESUME — ambil sisa detik dari DB, kirim ke Android
    // =====================================================================
    case 'resume':
        if ($trx_id) {
            $stmt_rg = $conn->prepare("SELECT id, status, jenis_paket, start_time, target_selesai, remaining_seconds FROM transactions WHERE id = ?");
            $stmt_rg->bind_param("i", $trx_id); $stmt_rg->execute();
            $resume_trx = $stmt_rg->get_result()->fetch_assoc(); $stmt_rg->close();

            if ($resume_trx && $resume_trx['status'] === 'paused') {
                $remaining     = max(1, (int)$resume_trx['remaining_seconds']);
                $customer_name = getCustomerName($conn, $trx_id);

                if ($resume_trx['jenis_paket'] == 'fixed') {
                    // ── FIX: UPDATE dulu, baca target_selesai aktual dari DB ──
                    $stmt_ru = $conn->prepare("UPDATE transactions SET status = 'ongoing', target_selesai = DATE_ADD(NOW(), INTERVAL ? SECOND), remaining_seconds = 0 WHERE id = ?");
                    $stmt_ru->bind_param("ii", $remaining, $trx_id); $stmt_ru->execute(); $stmt_ru->close();

                    // Baca target_selesai hasil UPDATE untuk sinkronisasi tepat
                    $stmt_tgt = $conn->prepare("SELECT UNIX_TIMESTAMP(target_selesai) as target_unix FROM transactions WHERE id = ?");
                    $stmt_tgt->bind_param("i", $trx_id); $stmt_tgt->execute();
                    $tgt_row    = $stmt_tgt->get_result()->fetch_assoc(); $stmt_tgt->close();
                    $sisa_detik = max(1, (int)$tgt_row['target_unix'] - time());

                    controlTV($ip, 'wake');
                    controlTV($ip, 'start_overlay', array_merge([
                        'action'   => 'TIMER',
                        'seconds'  => $sisa_detik,
                        'minutes'  => 0,
                        'customer' => $customer_name,
                        'rental'   => $rental_name,
                        'tv_no'    => $nama_tv,
                    ], $ov));
                } else {
                    // ── FIX OPEN BILL RESUME ──────────────────────────────────
                    // Mundurkan start_time agar elapsed tetap terhitung
                    $stmt_ru = $conn->prepare("UPDATE transactions SET status = 'ongoing', start_time = DATE_SUB(NOW(), INTERVAL ? SECOND), remaining_seconds = 0 WHERE id = ?");
                    $stmt_ru->bind_param("ii", $remaining, $trx_id); $stmt_ru->execute(); $stmt_ru->close();

                    // Baca start_time aktual dari DB setelah UPDATE
                    $stmt_st = $conn->prepare("SELECT UNIX_TIMESTAMP(start_time) as start_unix FROM transactions WHERE id = ?");
                    $stmt_st->bind_param("i", $trx_id); $stmt_st->execute();
                    $st_row     = $stmt_st->get_result()->fetch_assoc(); $stmt_st->close();
                    $start_unix = (int)$st_row['start_unix'];

                    controlTV($ip, 'wake');
                    // ── FIX: seconds=0 agar Android tahu ini mode count-up (open bill) ──
                    controlTV($ip, 'start_overlay', array_merge([
                        'action'          => 'TIMER',
                        'seconds'         => 0,
                        'minutes'         => 0,
                        'start_timestamp' => $start_unix,
                        'customer'        => $customer_name,
                        'rental'          => $rental_name,
                        'tv_no'           => $nama_tv,
                    ], $ov));
                }

                $stmt_tv = $conn->prepare("UPDATE tvs SET status = 'active' WHERE id = ?");
                $stmt_tv->bind_param("i", $tv_id); $stmt_tv->execute(); $stmt_tv->close();
                write_log($conn, 'RESUME', "$nama_tv | Trx #$trx_id | Sisa: {$remaining}d | Tipe: {$resume_trx['jenis_paket']}");
            }
        }
        if (isset($_REQUEST['ajax'])) {
            if (ob_get_length()) ob_clean();
            header('Content-Type: application/json');
            echo json_encode(['status' => 'success']);
            exit;
        }
        break;

    // --- PINDAH TV ---
    case 'move':
        $from_tv_id = (int)($_POST['from_tv_id'] ?? $_REQUEST['from_tv_id'] ?? 0);
        $to_tv_id   = (int)($_POST['to_tv_id']   ?? $_REQUEST['to_tv_id']   ?? 0);
        if ($from_tv_id && $to_tv_id && $from_tv_id !== $to_tv_id) {
            $from_tv     = getTVData($conn, $from_tv_id);
            $from_trx_id = $from_tv['current_trx_id'] ?? null;
            if ($from_trx_id) {
                $to_tv = getTVData($conn, $to_tv_id);
                if ($to_tv && $to_tv['status'] === 'available') {
                    $from_nama   = $from_tv['nama_tv']; $to_nama = $to_tv['nama_tv']; $from_status = $from_tv['status'];
                    $stmt_mv = $conn->prepare("UPDATE transactions SET tv_id = ? WHERE id = ?"); $stmt_mv->bind_param("ii", $to_tv_id, $from_trx_id); $stmt_mv->execute(); $stmt_mv->close();
                    $stmt_from = $conn->prepare("UPDATE tvs SET status = 'available', current_trx_id = NULL WHERE id = ?"); $stmt_from->bind_param("i", $from_tv_id); $stmt_from->execute(); $stmt_from->close();
                    $stmt_to   = $conn->prepare("UPDATE tvs SET status = ?, current_trx_id = ? WHERE id = ?"); $stmt_to->bind_param("sii", $from_status, $from_trx_id, $to_tv_id); $stmt_to->execute(); $stmt_to->close();
                    controlTV($from_tv['ip_address'], 'stop');
                    controlTV($from_tv['ip_address'], 'sleep');
                    if ($from_status === 'active') {
                        $customer_name = getCustomerName($conn, $from_trx_id);

                        // ── FIX: Baca target_selesai dari DB untuk sisa waktu akurat ──
                        $stmt_tgt = $conn->prepare("SELECT jenis_paket, UNIX_TIMESTAMP(target_selesai) as target_unix FROM transactions WHERE id = ?");
                        $stmt_tgt->bind_param("i", $from_trx_id); $stmt_tgt->execute();
                        $trx_data   = $stmt_tgt->get_result()->fetch_assoc(); $stmt_tgt->close();
                        $sisa_detik = ($trx_data['jenis_paket'] == 'fixed') ? max(1, (int)$trx_data['target_unix'] - time()) : 0;

                        controlTV($to_tv['ip_address'], 'wake');
                        controlTV($to_tv['ip_address'], 'start_overlay', array_merge([
                            'action'   => 'TIMER',
                            'seconds'  => $sisa_detik,
                            'minutes'  => 0,
                            'customer' => $customer_name,
                            'rental'   => $rental_name,
                            'tv_no'    => $to_nama,
                        ], $ov));
                    }
                    write_log($conn, 'MOVE', "$from_nama → $to_nama | Trx #$from_trx_id");
                }
            }
        }
        break;

    // --- STOP SESSION ---
    case 'stop':
        if ($trx_id) {
            $saved_trx_id = $trx_id;
            $stop_trx     = $conn->query("SELECT t.*, p.nama_paket, m.nama_member, m.saldo as member_saldo FROM transactions t LEFT JOIN packages p ON t.paket_id=p.id LEFT JOIN members m ON t.member_id=m.id WHERE t.id=$trx_id")->fetch_assoc();
            $stop_durasi  = max(0, time() - strtotime($stop_trx['start_time']));
            $stop_h       = floor($stop_durasi/3600); $stop_m = floor(($stop_durasi%3600)/60); $stop_s = $stop_durasi%60;
            $stop_dur_str = ($stop_h > 0 ? "{$stop_h}j " : "") . "{$stop_m}m {$stop_s}d";
            $biaya_sesi   = (int)$stop_trx['total_bayar'];
            if ($stop_trx['jenis_paket'] == 'open') {
                $r          = (int)$stop_trx['rate_per_jam'];
                $min_charge = (int)get_setting($conn, 'min_open_bill');
                $round_val  = (int)get_setting($conn, 'round_open_bill') ?: 100;
                $biaya_mentah = ($stop_durasi / 3600) * $r;
                $biaya_sesi   = max($min_charge, ceil($biaya_mentah / $round_val) * $round_val);
                $conn->query("UPDATE transactions SET total_bayar=$biaya_sesi WHERE id=$trx_id");
            }
            $fnb_total   = (int)($conn->query("SELECT SUM(total_harga) as total FROM orders_fnb WHERE trx_id=$trx_id")->fetch_assoc()['total'] ?? 0);
            $grand_total = $biaya_sesi + $fnb_total;
            $member_id   = $stop_trx['member_id'] ?? null; $payment_method = 'cash';
            if ($member_id) {
                $member_saldo = (int)($stop_trx['member_saldo'] ?? 0);
                if ($member_saldo >= $grand_total) {
                    $stmt_deduct = $conn->prepare("UPDATE members SET saldo = saldo - ? WHERE id = ?"); $stmt_deduct->bind_param("ii", $grand_total, $member_id); $stmt_deduct->execute(); $stmt_deduct->close();
                    $payment_method = 'saldo';
                } else if ($member_saldo > 0) {
                    $stmt_deduct = $conn->prepare("UPDATE members SET saldo = 0 WHERE id = ?"); $stmt_deduct->bind_param("i", $member_id); $stmt_deduct->execute(); $stmt_deduct->close();
                    $payment_method = 'partial';
                }
            }
            $conn->query("UPDATE transactions SET end_time=NOW(), status='completed' WHERE id=$trx_id");
            $conn->query("UPDATE tvs SET status='available', current_trx_id=NULL WHERE id=$tv_id");
            controlTV($ip, 'stop');
            controlTV($ip, 'sleep');
            write_log($conn, 'STOP_SESSION', "$nama_tv | Trx #$trx_id | Durasi: $stop_dur_str | Total: Rp ".number_format($grand_total)." | Bayar: $payment_method");
            if (isset($_REQUEST['ajax'])) {
                if (ob_get_length()) ob_clean(); header('Content-Type: application/json');
                echo json_encode(['status' => 'success', 'trx_id' => $saved_trx_id, 'payment_method' => $payment_method]); exit;
            }
        }
        break;

    // --- REMOTE CONTROL ---
    case 'adb_power':    controlTV($ip, 'power');    write_log($conn, 'REMOTE', "$nama_tv | Power"); break;
    case 'adb_vol_up':   controlTV($ip, 'vol_up');   write_log($conn, 'REMOTE', "$nama_tv | Vol Up"); break;
    case 'adb_vol_down': controlTV($ip, 'vol_down'); write_log($conn, 'REMOTE', "$nama_tv | Vol Down"); break;
    case 'adb_home':     controlTV($ip, 'home');     write_log($conn, 'REMOTE', "$nama_tv | Home"); break;
    case 'adb_connect':  controlTV($ip, 'connect');  write_log($conn, 'ADB_CONNECT', "$nama_tv | IP: $ip"); break;

    case 'check_adb_status':
        if (ob_get_length()) ob_clean(); header('Content-Type: application/json');
        $adb_list = getADBList(); $tvs_q = $conn->query("SELECT id, ip_address, nama_tv FROM tvs"); $res = [];
        while ($r = $tvs_q->fetch_assoc()) { $res[] = ['id'=>$r['id'],'nama'=>$r['nama_tv'],'status'=>checkADBStatus($r['ip_address'],$adb_list)]; }
        echo json_encode(['status'=>'success','tvs'=>$res]); exit;
}

if (isset($_REQUEST['ajax'])) { if (ob_get_length()) ob_clean(); echo "success"; exit; }
header($redirect); exit;