<?php // Vocal secours — WebRTC P2P + signalisation PHP + participants + PTT + VOX (gating via GainNode)
// Mutualisé OVH : nécessite ./data écrivable.
declare(strict_types=1);
require_once "auth/session.php";
require_once "includes/permissions.php";
header("X-Content-Type-Options: nosniff");
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: POST, GET, OPTIONS");
header("Access-Control-Allow-Headers: Content-Type");

$user = getCurrentUser();
$current_user_id = $user ? (int)$user["id"] : 0;

function room_id(string $s): string {
    $s = preg_replace("~[^a-zA-Z0-9_\-]~", "", $s);
    return $s !== "" ? $s : "secours";
}

function peer_id(): string {
    return bin2hex(random_bytes(8));
}

function now_ms(): int {
    return (int) floor(microtime(true) * 1000);
}

function json_out($data, int $code = 200): void {
    http_response_code($code);
    header("Content-Type: application/json; charset=utf-8");
    echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
    exit;
}

function get_room_participants(string $room): array {
    $ps = [];
    try {
        $stale_time = now_ms() - 30000;
        // Clean up stale sessions first
        db()->prepare("DELETE FROM voice_sessions WHERE last_seen < ?")->execute([$stale_time]);

        $stmt = db()->prepare("
            SELECT vs.peer_id as id, vs.user_id, vs.name, vs.last_seen, vs.is_muted, vs.is_deafened, u.avatar_url 
            FROM voice_sessions vs
            LEFT JOIN users u ON vs.user_id = u.id
            WHERE vs.channel_id = ? AND vs.last_seen > ?
        ");
        $stmt->execute([$room, $stale_time]);
        $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
        foreach ($rows as $r) {
            $r['user_id'] = (int)$r['user_id'];
            $r['last_seen'] = (int)$r['last_seen'];
            $r['is_muted'] = (int)$r['is_muted'];
            $r['is_deafened'] = (int)$r['is_deafened'];
            $ps[$r['id']] = $r;
        }
    } catch (Exception $e) {
        error_log("get_room_participants error: " . $e->getMessage());
    }
    return $ps;
}

// Logic for signaling
$action = $_REQUEST["action"] ?? "";
$room = room_id($_REQUEST["room"] ?? "secours");
$my_id = $_REQUEST["peer_id"] ?? "";

if ($action === "join") {
    $name = $_REQUEST["name"] ?? "User";
    $new_id = substr($_REQUEST["peer_id"] ?: peer_id(), 0, 16);
    
    // DB Integration for sidebar and participation
    if ($current_user_id > 0) {
        try {
            $stmt = db()->prepare("INSERT INTO voice_sessions (user_id, channel_id, last_seen, peer_id, name) VALUES (?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE channel_id = ?, last_seen = ?, peer_id = ?, name = ?");
            $stmt->execute([$current_user_id, $room, now_ms(), $new_id, $name, $room, now_ms(), $new_id, $name]);
        } catch (Exception $e) {
            error_log("Voice session DB error: " . $e->getMessage());
        }
    }
    
    $ps = get_room_participants($room);
    
    json_out(["success" => true, "peer_id" => $new_id, "participants" => $ps, "can_speak" => Permissions::canDoInChannel($current_user_id, (int)$room, Permissions::SPEAK)]);
}

if ($action === "poll") {
    if (!$my_id) json_out(["error" => "Missing peer_id"], 400);
    
    $is_muted = isset($_REQUEST["is_muted"]) ? (int)$_REQUEST["is_muted"] : 0;
    $is_deafened = isset($_REQUEST["is_deafened"]) ? (int)$_REQUEST["is_deafened"] : 0;

    $can_speak = Permissions::canDoInChannel($current_user_id, (int)$room, Permissions::SPEAK);
    if (!$can_speak) $is_muted = 1;

    // Update DB last_seen
    if ($current_user_id > 0) {
        try {
            $stmt = db()->prepare("UPDATE voice_sessions SET last_seen = ?, is_muted = ?, is_deafened = ?, channel_id = ?, peer_id = ?, name = ? WHERE user_id = ?");
            $name = $_REQUEST["name"] ?? ($user["display_name"] ?: $user["username"] ?: "User");
            $stmt->execute([now_ms(), $is_muted, $is_deafened, $room, $my_id, $name, $current_user_id]);
            
            // If update failed (no rows affected because session was deleted or user_id mismatch), re-insert
            if ($stmt->rowCount() === 0) {
                $stmt = db()->prepare("INSERT INTO voice_sessions (user_id, channel_id, last_seen, peer_id, name, is_muted, is_deafened) VALUES (?, ?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE channel_id = ?, last_seen = ?, peer_id = ?, name = ?, is_muted = ?, is_deafened = ?");
                $stmt->execute([$current_user_id, $room, now_ms(), $my_id, $name, $is_muted, $is_deafened, $room, now_ms(), $my_id, $name, $is_muted, $is_deafened]);
            }
        } catch (Exception $e) {}
    }
    
    $ps = get_room_participants($room);
    
    // Read signals from DB
    $signals = [];
    try {
        $stmt = db()->prepare("SELECT id, from_peer_id as `from`, data FROM voice_signals WHERE to_peer_id = ? ORDER BY id ASC");
        $stmt->execute([$my_id]);
        $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
        
        if (!empty($rows)) {
            $ids = [];
            foreach ($rows as $r) {
                $signals[] = [
                    "from" => $r["from"],
                    "data" => json_decode($r["data"], true)
                ];
                $ids[] = $r["id"];
            }
            // Delete signals we just read
            $placeholders = implode(',', array_fill(0, count($ids), '?'));
            $stmt_del = db()->prepare("DELETE FROM voice_signals WHERE id IN ($placeholders)");
            $stmt_del->execute($ids);
        }
        
        // Periodic cleanup of old signals (> 1 minute)
        if (rand(1, 20) === 1) {
            $old_time = now_ms() - 60000;
            $stmt_clean = db()->prepare("DELETE FROM voice_signals WHERE created_at_ms < ?");
            $stmt_clean->execute([$old_time]);
        }
    } catch (Exception $e) {
        error_log("Signal poll error: " . $e->getMessage());
    }
    
    json_out([
        "success" => true, 
        "participants" => $ps, 
        "signals" => $signals, 
        "can_speak" => $can_speak
    ]);
}

if ($action === "signal") {
    if (!$my_id) json_out(["error" => "Missing peer_id"], 400);
    $to = $_REQUEST["to"] ?? "";
    $data = $_REQUEST["data"] ?? "";
    if (!$to || !$data) json_out(["error" => "Missing to/data"], 400);
    
    try {
        $stmt = db()->prepare("INSERT INTO voice_signals (room_id, from_peer_id, to_peer_id, data, created_at_ms) VALUES (?, ?, ?, ?, ?)");
        $stmt->execute([$room, $my_id, $to, $data, now_ms()]);
        json_out(["success" => true]);
    } catch (Exception $e) {
        json_out(["error" => "Signal send failed: " . $e->getMessage()], 500);
    }
}

if ($action === "list_all") {
    // Periodic cleanup of the DB table (stale sessions > 15s)
    if (rand(1, 10) === 1) {
        try {
            $stale_db_time = now_ms() - 30000;
            $stmt = db()->prepare("DELETE FROM voice_sessions WHERE last_seen < ?");
            $stmt->execute([$stale_db_time]);
        } catch (Exception $e) {}
    }

    try {
        $stmt = db()->prepare("
            SELECT vs.channel_id, vs.user_id, vs.is_muted, vs.is_deafened, u.username, u.display_name, u.avatar_url 
            FROM voice_sessions vs
            JOIN users u ON vs.user_id = u.id
            WHERE vs.last_seen > ?
        ");
        $stale_db_time = now_ms() - 30000;
        $stmt->execute([$stale_db_time]);
        $sessions = $stmt->fetchAll(PDO::FETCH_ASSOC);
        
        $by_channel = [];
        foreach ($sessions as $s) {
            $by_channel[$s['channel_id']][] = $s;
        }
        json_out(["success" => true, "channels" => $by_channel]);
    } catch (Exception $e) {
        json_out(["error" => $e->getMessage()], 500);
    }
}

if ($action === "leave") {
    if ($current_user_id > 0) {
        try {
            $stmt = db()->prepare("DELETE FROM voice_sessions WHERE user_id = ?");
            $stmt->execute([$current_user_id]);
        } catch (Exception $e) {}
    }
    json_out(["success" => true]);
}

if ($action === "get_whispers") {
    if ($current_user_id <= 0) json_out(["error" => "Unauthorized"], 401);
    try {
        $stmt = db()->prepare("SELECT * FROM voice_whispers WHERE user_id = ?");
        $stmt->execute([$current_user_id]);
        json_out(["success" => true, "whispers" => $stmt->fetchAll(PDO::FETCH_ASSOC)]);
    } catch (Exception $e) {
        json_out(["error" => $e->getMessage()], 500);
    }
}

if ($action === "save_whisper") {
    if ($current_user_id <= 0) json_out(["error" => "Unauthorized"], 401);
    $target_type = $_REQUEST["target_type"] ?? "";
    $target_id = (int)($_REQUEST["target_id"] ?? 0);
    $key = $_REQUEST["key"] ?? "";
    
    if (!$target_type || !$target_id || !$key) json_out(["error" => "Missing parameters"], 400);
    
    try {
        $stmt = db()->prepare("INSERT INTO voice_whispers (user_id, target_type, target_id, whisper_key) VALUES (?, ?, ?, ?) ON DUPLICATE KEY UPDATE target_type = ?, target_id = ?, whisper_key = ?");
        $stmt->execute([$current_user_id, $target_type, $target_id, $key, $target_type, $target_id, $key]);
        json_out(["success" => true]);
    } catch (Exception $e) {
        json_out(["error" => $e->getMessage()], 500);
    }
}

if ($action === "delete_whisper") {
    if ($current_user_id <= 0) json_out(["error" => "Unauthorized"], 401);
    $id = (int)($_REQUEST["id"] ?? 0);
    try {
        $stmt = db()->prepare("DELETE FROM voice_whispers WHERE id = ? AND user_id = ?");
        $stmt->execute([$id, $current_user_id]);
        json_out(["success" => true]);
    } catch (Exception $e) {
        json_out(["error" => $e->getMessage()], 500);
    }
}

if ($action === "find_whisper_targets") {
    if ($current_user_id <= 0) json_out(["error" => "Unauthorized"], 401);
    $target_type = $_REQUEST["target_type"] ?? "";
    $target_id = $_REQUEST["target_id"] ?? ""; // Can be channel name or user_id
    
    if (!$target_type || !$target_id) json_out(["error" => "Missing parameters"], 400);
    
    try {
        $stale_time = now_ms() - 30000;
        if ($target_type === 'user') {
            $stmt = db()->prepare("SELECT peer_id, name FROM voice_sessions WHERE user_id = ? AND last_seen > ?");
            $stmt->execute([(int)$target_id, $stale_time]);
        } else {
            // target_id is channel_id (room)
            $stmt = db()->prepare("SELECT peer_id, name FROM voice_sessions WHERE channel_id = ? AND last_seen > ?");
            $stmt->execute([(string)$target_id, $stale_time]);
        }
        json_out(["success" => true, "targets" => $stmt->fetchAll(PDO::FETCH_ASSOC)]);
    } catch (Exception $e) {
        json_out(["error" => $e->getMessage()], 500);
    }
}

json_out(["error" => "Unknown action"], 404);
