use base64::{Engine as _, engine::general_purpose::STANDARD};
const CHUNK_SIZE: usize = 4000;
pub fn encode_placement(png_bytes: &[u8], cols: u16, rows: u16) -> Result<String, String> {
let b64 = STANDARD.encode(png_bytes);
let mut out = String::with_capacity(b64.len() + 256);
let mut chars = b64.as_bytes();
let mut first = true;
while !chars.is_empty() {
let take = chars.len().min(CHUNK_SIZE);
let (chunk, rest) = chars.split_at(take);
let more = if rest.is_empty() { 0 } else { 1 };
if first {
out.push_str(&format!("\x1b_Ga=T,f=100,c={cols},r={rows},m={more};"));
first = false;
} else {
out.push_str(&format!("\x1b_Gm={more};"));
}
out.push_str(std::str::from_utf8(chunk).map_err(|e| e.to_string())?);
out.push_str("\x1b\\");
chars = rest;
}
Ok(out)
}
pub fn clear_all() -> &'static str {
"\x1b_Ga=d\x1b\\"
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn encode_small_png_in_single_chunk() {
let bytes = vec![0u8; 100];
let s = encode_placement(&bytes, 20, 10).unwrap();
assert!(s.starts_with("\x1b_Ga=T,f=100,c=20,r=10,m=0;"));
assert!(s.ends_with("\x1b\\"));
}
#[test]
fn encode_large_png_in_multiple_chunks() {
let bytes = vec![0u8; 4000];
let s = encode_placement(&bytes, 20, 10).unwrap();
assert!(s.contains("m=1;"), "expected m=1 in continuation: {s}");
assert!(s.contains(",m=1;"), "first chunk should have m=1: {s}");
assert!(s.ends_with("\x1b\\"));
let count = s.matches("\x1b\\").count();
assert!(count >= 2, "expected ≥2 chunks, got {count}");
}
}