//! Embedded VM exposed as a normal localhost TCP service.
//!
//! ```sh
//! supermachine bundle --into /tmp/my-bundles --image nginx:1.27-alpine
//! cargo supermachine build --release --example tcp_forward
//! target/release/examples/tcp_forward /tmp/my-bundles/nginx_1_27-alpine 9090
//! curl http://127.0.0.1:9090/
//! ```
//!
//! Compared to `bundle_load`: instead of the embedder driving
//! `vm.connect()` directly, the library binds a TCP listener and
//! forwards every accepted connection to the guest. The embedder's
//! own users / threads / HTTP clients see a normal localhost
//! service.

use std::io::{Read, Write};
use std::net::TcpStream;
use std::time::{Duration, Instant};

use supermachine::{Image, Vm, VmConfig};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let bundle_dir = std::env::args()
        .nth(1)
        .ok_or("usage: tcp_forward <BUNDLE_DIR> [HOST_PORT]")?;
    let host_port: u16 = std::env::args()
        .nth(2)
        .map(|s| s.parse())
        .transpose()?
        .unwrap_or(0);

    let t0 = Instant::now();
    let image = Image::from_snapshot(&bundle_dir)?;
    let vm = Vm::start(&image, &VmConfig::new())?;
    eprintln!("vm started in {:?}", t0.elapsed());

    let fwd = vm.expose_tcp(host_port, 80)?;
    eprintln!("listening on {} → guest", fwd.local_addr());

    // Self-test: hit our own listener like a normal HTTP client.
    let mut tcp = TcpStream::connect(fwd.local_addr())?;
    tcp.set_read_timeout(Some(Duration::from_secs(2)))?;
    tcp.write_all(b"GET / HTTP/1.1\r\nHost: workload\r\nConnection: close\r\n\r\n")?;
    let mut response = Vec::new();
    tcp.read_to_end(&mut response)?;
    let preview = String::from_utf8_lossy(&response);
    for line in preview.lines().take(4) {
        eprintln!("  {line}");
    }

    drop(fwd); // stop accepting new conns
    vm.stop()?;
    eprintln!("done in {:?}", t0.elapsed());
    Ok(())
}
