Skip to content
use serde::{Deserialize, Serialize};
use uuid::Uuid;

#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
pub enum Lang {
    Rust,
    Kotlin,
}

impl Lang {
    pub fn as_str(&self) -> &'static str {
        match self {
            Lang::Rust => "rust",
            Lang::Kotlin => "kotlin",
        }
    }

    pub fn from_str(s: &str) -> Self {
        match s {
            "rust" => Lang::Rust,
            _ => Lang::Kotlin,
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Code {
    pub id: String,
    pub path: String,
    pub lang: Lang,
    pub raw: String,
    pub wasm: Vec<u8>,
    pub hurl: String,
    pub user_id: String,
    pub created_at: u64,
    pub updated_at: u64,
}

impl Code {
    pub fn new(path: impl Into<String>, raw: impl Into<String>, lang: Lang, wasm: Vec<u8>) -> Self {
        let now = std::time::SystemTime::now()
            .duration_since(std::time::UNIX_EPOCH)
            .unwrap_or_default()
            .as_secs();
        Self {
            id: Uuid::new_v4().to_string(),
            path: path.into(),
            lang,
            raw: raw.into(),
            wasm,
            hurl: String::new(),
            user_id: String::new(),
            created_at: now,
            updated_at: now,
        }
    }

    pub fn id(&self) -> &str {
        &self.id
    }

    pub fn path(&self) -> &str {
        &self.path
    }

    pub fn lang(&self) -> &Lang {
        &self.lang
    }

    pub fn raw(&self) -> &str {
        &self.raw
    }

    pub fn wasm(&self) -> &[u8] {
        &self.wasm
    }

    pub fn hurl(&self) -> &str {
        &self.hurl
    }

    pub fn user_id(&self) -> &str {
        &self.user_id
    }

    pub fn created_at(&self) -> u64 {
        self.created_at
    }

    pub fn updated_at(&self) -> u64 {
        self.updated_at
    }

    pub fn set_path(&mut self, path: impl Into<String>) {
        self.path = path.into();
        self.touch();
    }

    pub fn set_revision(&mut self, raw: impl Into<String>, lang: Lang, wasm: Vec<u8>) {
        self.raw = raw.into();
        self.lang = lang;
        self.wasm = wasm;
        self.touch();
    }

    fn touch(&mut self) {
        self.updated_at = std::time::SystemTime::now()
            .duration_since(std::time::UNIX_EPOCH)
            .unwrap_or_default()
            .as_secs();
    }
}

impl Default for Code {
    fn default() -> Self {
        let now = std::time::SystemTime::now()
            .duration_since(std::time::UNIX_EPOCH)
            .unwrap_or_default()
            .as_secs();
        Self {
            id: Uuid::new_v4().to_string(),
            path: "/_test".to_string(),
            lang: Lang::Kotlin,
            raw: String::new(),
            wasm: Vec::new(),
            hurl: String::new(),
            user_id: String::new(),
            created_at: now,
            updated_at: now,
        }
    }
}

pub const MAX_VERSIONS: i32 = 5;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CodeVersion {
    pub id: String,
    pub endpoint_id: String,
    pub version: i32,
    pub raw: String,
    pub lang: Lang,
    #[serde(skip)]
    pub wasm: Vec<u8>,
    pub created_at: u64,
}

impl CodeVersion {
    pub fn new(endpoint_id: &str, version: i32, raw: impl Into<String>, lang: Lang, wasm: Vec<u8>) -> Self {
        let now = std::time::SystemTime::now()
            .duration_since(std::time::UNIX_EPOCH)
            .unwrap_or_default()
            .as_secs();
        Self {
            id: Uuid::new_v4().to_string(),
            endpoint_id: endpoint_id.to_string(),
            version,
            raw: raw.into(),
            lang,
            wasm,
            created_at: now,
        }
    }

    pub fn id(&self) -> &str { &self.id }
    pub fn endpoint_id(&self) -> &str { &self.endpoint_id }
    pub fn version(&self) -> i32 { self.version }
    pub fn raw(&self) -> &str { &self.raw }
    pub fn lang(&self) -> &Lang { &self.lang }
    pub fn wasm(&self) -> &[u8] { &self.wasm }
    pub fn created_at(&self) -> u64 { self.created_at }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TestVersion {
    pub id: String,
    pub endpoint_id: String,
    pub version: i32,
    pub hurl: String,
    pub created_at: u64,
}

impl TestVersion {
    pub fn new(endpoint_id: &str, version: i32, hurl: impl Into<String>) -> Self {
        let now = std::time::SystemTime::now()
            .duration_since(std::time::UNIX_EPOCH)
            .unwrap_or_default()
            .as_secs();
        Self {
            id: Uuid::new_v4().to_string(),
            endpoint_id: endpoint_id.to_string(),
            version,
            hurl: hurl.into(),
            created_at: now,
        }
    }

    pub fn id(&self) -> &str { &self.id }
    pub fn endpoint_id(&self) -> &str { &self.endpoint_id }
    pub fn version(&self) -> i32 { self.version }
    pub fn hurl(&self) -> &str { &self.hurl }
    pub fn created_at(&self) -> u64 { self.created_at }
}

pub const DEFAULT_KOTLIN_CODE: &str = r#"fun main() {
    val name = getQueryParam("name") ?: "World"
    val response = """{"message": "Hello, $name!", "timestamp": "${getTimestamp()}"}"""
    respond(200, response)
}

fun getQueryParam(name: String): String? {
    return null
}

fun getTimestamp(): String {
    return "2024-01-01T00:00:00Z"
}

fun respond(status: Int, body: String) {
    println(body)
}"#;