use std::{
    net::TcpListener,
    sync::{
        atomic::{self, AtomicBool},
        Arc,
    },
    thread::available_parallelism,
};

use crate::{handlers::handle_connection, routing::Route, threading::ThreadPool};

pub struct PreMountConfig {
    address: TcpListener,
    workers: usize,
    threadpool: ThreadPool,
}
impl PreMountConfig {
    pub fn mount(self, mountpoint: &str, routes: Vec<Route>) -> Config {
        Config {
            mountpoint,
            address: self.address,
            workers: self.workers,
            threadpool: self.threadpool,
            routes,
        }
    }
}
pub struct Config<'a> {
    mountpoint: &'a str,
    address: TcpListener,
    workers: usize,
    threadpool: ThreadPool,
    routes: Vec<Route>,
}

impl Config<'_> {
    pub fn launch(self) {
        let running = Arc::new(AtomicBool::new(true));

        // Clone a reference to `running` to pass to the signal handler closure
        let running_for_handler = running.clone();

        // Set up a signal handler for SIGINT
        ctrlc::set_handler(move || {
            // When the user sends a SIGINT signal (e.g. by pressing CTRL+C),
            // set the `running` flag to false to initiate a graceful shutdown
            println!("SIGNIT received, shutting down gracefully");
            running_for_handler.store(false, atomic::Ordering::SeqCst);
        })
        .expect("Error setting Ctrl-C handler");

        for stream in self.address.incoming() {
            if !running.load(atomic::Ordering::SeqCst) {
                break;
            }
            let stream = stream.unwrap();
            self.threadpool.execute(|| handle_connection(stream))
        }
    }
}
pub fn build(ip: &str) -> PreMountConfig {
    let listener = TcpListener::bind(ip).unwrap();
    let ip = ip.splitn(2, ":").collect::<Vec<&str>>();
    if ip.len() != 2 {
        panic!("Invalid IP Address");
    }
    let port = ip[1];
    let ip = ip[0];
    let workers = available_parallelism().unwrap().get();
    let threadpool = ThreadPool::new(workers);
    println!(
        "\x1b[34m⚙ Configuration\x1b[0m
  >> \x1b[34mIp\x1b[0m: {ip}
  >> \x1b[34mPort\x1b[0m: {port}
  >> \x1b[34mWorkers\x1b[0m: {workers}
\n
Server has launched from {ip}:{port}.
"
    );
    PreMountConfig {
        address: listener,
        workers,
        threadpool,
    }
}