use regex::Regex;
use std::collections::HashMap;
use std::fs;
pub fn render_template(file: &str, context: &HashMap<&str, &str>) -> String {
let mut contents = load_template(file);
let extends_re = Regex::new(r"\{%\s*extends\s*'([^']+)'\s*%\}").unwrap();
if let Some(caps) = extends_re.captures(&contents) {
let base_file = &caps[1];
let base_contents = load_template(base_file);
let block_re =
Regex::new(r"\{%\s*block\s+(\w+)\s*%\}(?s)(.*?)\{%\s*endblock\s*%\}").unwrap();
let mut blocks = HashMap::new();
for caps in block_re.captures_iter(&contents) {
blocks.insert(caps[1].to_string(), caps[2].to_string());
}
let base_block_re =
Regex::new(r"\{%\s*block\s+(\w+)\s*%\}(?s)(.*?)\{%\s*endblock\s*%\}").unwrap();
contents = base_block_re
.replace_all(&base_contents, |caps: ®ex::Captures| {
blocks
.get(&caps[1])
.cloned()
.unwrap_or_else(|| caps[2].to_string())
})
.to_string();
}
let include_re = Regex::new(r"\{%\s*include\s*'([^']+)'\s*%\}").unwrap();
contents = include_re
.replace_all(&contents, |caps: ®ex::Captures| load_template(&caps[1]))
.to_string();
let var_re = Regex::new(r"\{\{\s*(\w+)\s*\}\}").unwrap();
contents = var_re
.replace_all(&contents, |caps: ®ex::Captures| {
context.get(&caps[1]).copied().unwrap_or("")
})
.to_string();
if crate::is_dev_mode() {
let reload_script = r#"
<script>
const ws = new WebSocket("ws://localhost:35729");
ws.onopen = () => console.log("✅ LiveReload connected");
ws.onmessage = () => {
console.log("🔁 Reloading...");
location.reload();
};
ws.onerror = (e) => console.error("❌ WebSocket error", e);
</script>
"#;
if contents.contains("</body>") {
contents = contents.replace("</body>", &format!("{}{}", reload_script, "</body>"));
} else {
contents.push_str(reload_script);
}
}
contents
}
fn load_template(file: &str) -> String {
let path = format!("templates/{}", file);
fs::read_to_string(path).unwrap_or_else(|_| format!("<h1>Template '{}' not found</h1>", file))
}