use rand::{thread_rng, Rng};
use std::sync::Arc;
use tapir_cwtch::acns::tor::authentication::HashedPassword;
use tapir_cwtch::acns::tor::run::TorRunner;
use tapir_cwtch::acns::tor::torrc::TorrcGenerator;
use tapir_cwtch::acns::tor::TorProcess;
use tapir_cwtch::applications::authentication_app::AuthenicationApp;
use tapir_cwtch::connections::service::Service;
use tapir_cwtch::connections::{Connection, ConnectionInterface, InboundConnection};
use tapir_cwtch::primitives::identity::Identity;
use tapir_cwtch::primitives::transcript::Transcript;

fn main() {
    let tor_path = which::which("tor");
    let mut rng = thread_rng();
    let socks_port = rng.gen_range(10052, 11100);
    let control_port = rng.gen_range(9052, 9100);
    let mut tor_runner = TorRunner::run(
        TorrcGenerator::new()
            .with_socks_port(socks_port)
            .with_control_port(control_port)
            .with_hashed_control_password("examplehashedpassword"),
        "./example_server_rc",
        tor_path.unwrap().to_str().unwrap(),
        "./examples/server_data_dir/",
    )
    .unwrap();
    tor_runner.wait_until_bootstrapped();

    let mut auth_control_port = TorProcess::connect(control_port)
        .unwrap()
        .authenticate(Box::new(HashedPassword::new(String::from("examplehashedpassword"))))
        .unwrap();
    let identity = Arc::new(Identity::initialize_ephemeral_identity());
    match identity.host_onion_service(&mut auth_control_port, 9878, 10029) {
        Ok(service_id) => {
            // we authenticated!

            println!("Service Id: {}", service_id);
            println!("Setup: {}", identity.hostname());

            let service = Service::init(identity.clone(), 0);

            let inbound_service = |conn: Connection<InboundConnection>| {
                let mut transcript = Transcript::new_transcript("tapir-transcript");
                let mut auth_app = AuthenicationApp::new(identity);
                match auth_app.run_inbound(conn, &mut transcript) {
                    Ok(conn) => println!("Authenticated Inbound Connection from {}", conn.hostname()),
                    _ => println!("Failed Inbound Authentication"),
                }
            };

            let mut _service = service.listen(10029, inbound_service.clone()).unwrap_or_else(|_| panic!());

            loop {}
        }
        Err(err) => println!("{:?}", err),
    }
}
