use actix_web::{App, HttpServer};
use clap::Parser;
use webterm::WebTermExt;

use std::process::Command;

#[derive(Parser, Debug)]
#[command(name = "webterm-server")]
#[command(about = "Web terminal server based on xterm.js")]
struct Opt {
    /// The port to listen on
    #[arg(short, long, default_value = "8082")]
    port: u16,

    /// The host or IP to listen on
    #[arg(short = 'H', long, default_value = "localhost")]
    host: String,

    /// The command to execute
    #[arg(short, long, default_value = "/bin/sh")]
    command: String,
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    env_logger::init();

    let opt = Opt::parse();

    // Normalize common hostnames that sometimes resolve to IPv6-only addresses
    // which can cause platform-specific bind failures. Mapping `localhost` to
    // 127.0.0.1 makes behavior predictable on systems where `::1` would otherwise
    // be selected.
    let host = if opt.host == "localhost" {
        "127.0.0.1".to_string()
    } else {
        opt.host.clone()
    };

    let bind_addr = format!("{}:{}", host, opt.port);
    println!("Starting webterm server on http://{}", bind_addr);

    let command = opt.command.clone();

    HttpServer::new(move || {
        let cmd = command.clone();
        App::new()
            .service(actix_files::Files::new("/assets", "./static"))
            .service(actix_files::Files::new("/static", "./node_modules"))
            .webterm_socket("/websocket", move |_req| {
                let mut command = Command::new(&cmd);
                command.env("TERM", "xterm");
                command
            })
            .webterm_ui("/", "/websocket", "/static")
    })
    .bind(&bind_addr)?
    .run()
    .await
}
