// LiveKit-integrasjon — token-generering for sanntidslyd.
//
// Genererer JWT access tokens som gir brukere tilgang til LiveKit-rom.
// Tokens signeres med LIVEKIT_API_SECRET (HMAC-SHA256) og inneholder
// grants som bestemmer hva deltakeren kan gjøre (publisere, lytte, etc.).
//
// Ref: docs/concepts/møterommet.md, docs/concepts/studioet.md

use jsonwebtoken::{encode, EncodingKey, Header, Algorithm};
use serde::{Deserialize, Serialize};
use uuid::Uuid;

/// LiveKit video grant — bestemmer hva en deltaker kan gjøre i et rom.
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
struct VideoGrant {
    room: String,
    room_join: bool,
    can_publish: bool,
    can_subscribe: bool,
}

/// JWT claims for LiveKit access token.
#[derive(Serialize)]
struct LiveKitClaims {
    /// API Key (issuer)
    iss: String,
    /// Participant identity
    sub: String,
    /// Participant name (display)
    name: String,
    /// Issued at (unix timestamp)
    iat: u64,
    /// Not before (unix timestamp)
    nbf: u64,
    /// Expiration (unix timestamp)
    exp: u64,
    /// LiveKit video grant
    video: VideoGrant,
    /// Metadata (JSON string)
    #[serde(skip_serializing_if = "String::is_empty")]
    metadata: String,
}

/// Rolle i et LiveKit-rom. Bestemmer publiserings-rettigheter.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum RoomRole {
    /// Kan publisere og lytte (host, deltaker)
    Publisher,
    /// Kan bare lytte (observatør)
    Subscriber,
}

/// Resultat fra token-generering.
pub struct LiveKitToken {
    pub room_name: String,
    pub token: String,
    pub identity: String,
}

/// Generer et LiveKit access token for en deltaker.
///
/// - `communication_id`: UUID for kommunikasjonsnoden (brukes til rom-navn)
/// - `user_id`: Brukerens node_id (brukes som identity)
/// - `display_name`: Visningsnavn for deltakeren
/// - `role`: Publisher (kan sende lyd) eller Subscriber (bare lytte)
/// - `ttl_secs`: Token-levetid i sekunder (typisk 3600 = 1 time)
pub fn generate_token(
    communication_id: Uuid,
    user_id: Uuid,
    display_name: &str,
    role: RoomRole,
    ttl_secs: u64,
) -> Result<LiveKitToken, String> {
    let api_key = std::env::var("LIVEKIT_API_KEY")
        .map_err(|_| "LIVEKIT_API_KEY ikke satt".to_string())?;
    let api_secret = std::env::var("LIVEKIT_API_SECRET")
        .map_err(|_| "LIVEKIT_API_SECRET ikke satt".to_string())?;

    let room_name = format!("communication_{communication_id}");
    let identity = user_id.to_string();
    let now = std::time::SystemTime::now()
        .duration_since(std::time::UNIX_EPOCH)
        .unwrap()
        .as_secs();

    let can_publish = role == RoomRole::Publisher;

    let claims = LiveKitClaims {
        iss: api_key,
        sub: identity.clone(),
        name: display_name.to_string(),
        iat: now,
        nbf: now,
        exp: now + ttl_secs,
        video: VideoGrant {
            room: room_name.clone(),
            room_join: true,
            can_publish,
            can_subscribe: true,
        },
        metadata: String::new(),
    };

    let header = Header::new(Algorithm::HS256);
    let key = EncodingKey::from_secret(api_secret.as_bytes());

    let token = encode(&header, &claims, &key)
        .map_err(|e| format!("Kunne ikke generere LiveKit-token: {e}"))?;

    Ok(LiveKitToken {
        room_name,
        token,
        identity,
    })
}

/// Sjekk om LiveKit-serveren er tilgjengelig.
pub async fn health_check() -> Result<bool, String> {
    let url = std::env::var("LIVEKIT_URL")
        .unwrap_or_else(|_| "http://localhost:7880".to_string());

    match reqwest::Client::new()
        .get(&url)
        .timeout(std::time::Duration::from_secs(3))
        .send()
        .await
    {
        Ok(_) => Ok(true),
        Err(e) => Err(format!("LiveKit utilgjengelig: {e}")),
    }
}
