//! Server module for handling HTTP requests and managing web server lifecycle.
//! 
//! This module provides the core server functionality including:
//! - Server builder pattern for configuration
//! - HTTP request routing and handling
//! - Connection management and error handling
//! - Default request handling
//! 
//! # Examples
//! 
//! ```no_run
//! use micro_web::{Server, router::{Router, get}, handler_fn};
//! 
//! async fn hello_world() -> &'static str {
//!     "Hello, World!"
//! }
//! 
//! #[tokio::main]
//! async fn main() {
//!     let router = Router::builder()
//!         .route("/", get(handler_fn(hello_world)))
//!         .build();
//!         
//!     Server::builder()
//!         .router(router)
//!         .bind("127.0.0.1:3000")
//!         .build()
//!         .unwrap()
//!         .start()
//!         .await;
//! }
//! ```

use crate::handler::RequestHandler;
use crate::router::Router;
use crate::{handler_fn, OptionReqBody, RequestContext, ResponseBody};
use http::{Request, Response, StatusCode};
use micro_http::connection::HttpConnection;
use micro_http::handler::Handler;
use micro_http::protocol::body::ReqBody;
use micro_http::protocol::RequestHeader;
use std::error::Error;
use std::future::Future;
use std::net::{SocketAddr, ToSocketAddrs};
use std::pin::Pin;
use std::sync::Arc;
use thiserror::Error;
use tokio::net::TcpListener;
use tracing::{error, info, warn, Level};
use tracing_subscriber::FmtSubscriber;

/// Builder for configuring and constructing a [`Server`] instance.
/// 
/// The builder provides a fluent API for setting server options including:
/// - Binding address
/// - Request router
/// - Default request handler
pub struct ServerBuilder {
    router: Option<Router>,
    default_handler: Option<Box<dyn RequestHandler>>,
    address: Option<Vec<SocketAddr>>,
}

impl ServerBuilder {
    fn new() -> Self {
        Self { router: None, default_handler: None, address: None }
    }

    pub fn bind<A: ToSocketAddrs>(mut self, address: A) -> Self {
        self.address = Some(address.to_socket_addrs().unwrap().collect::<Vec<_>>());
        self
    }

    pub fn router(mut self, router: Router) -> Self {
        self.router = Some(router);
        self
    }

    pub fn default_handler(mut self, request_handler: impl RequestHandler + 'static) -> Self {
        self.default_handler = Some(Box::new(request_handler));
        self
    }

    pub fn build(self) -> Result<Server, ServerBuildError> {
        let new_builder =
            if let None = self.default_handler { self.default_handler(handler_fn(default_handler)) } else { self };
        let router = new_builder.router.ok_or(ServerBuildError::MissingRouter)?;
        let address = new_builder.address.ok_or(ServerBuildError::MissingAddress)?;

        // unwrap is safe here because we set it in the new_builder
        Ok(Server { router, default_handler: new_builder.default_handler.unwrap(), address })
    }
}

async fn default_handler() -> (StatusCode, &'static str) {
    (StatusCode::NOT_FOUND, "404 Not Found")
}

/// Core server implementation that processes HTTP requests.
/// 
/// The server is responsible for:
/// - Listening for incoming connections
/// - Routing requests to appropriate handlers
/// - Managing connection lifecycle
/// - Error handling and logging
/// 
pub struct Server {
    router: Router,
    default_handler: Box<dyn RequestHandler>,
    address: Vec<SocketAddr>,
}

/// Errors that can occur during server construction.
#[derive(Error, Debug)]
pub enum ServerBuildError {
    /// Router was not configured
    #[error("router must be set")]
    MissingRouter,
    
    /// Bind address was not configured
    #[error("address must be set")]
    MissingAddress,
}

impl Server {
    pub fn builder() -> ServerBuilder {
        ServerBuilder::new()
    }

    pub async fn start(self) {
        let subscriber = FmtSubscriber::builder().with_max_level(Level::INFO).finish();
        tracing::subscriber::set_global_default(subscriber).expect("setting default subscriber failed");

        info!("start listening at {:?}", self.address);
        let tcp_listener = match TcpListener::bind(self.address.as_slice()).await {
            Ok(tcp_listener) => tcp_listener,
            Err(e) => {
                error!(cause = %e, "bind server error");
                return;
            }
        };

        let handler = Arc::new(self);
        loop {
            let (tcp_stream, _remote_addr) = match tcp_listener.accept().await {
                Ok(stream_and_addr) => stream_and_addr,
                Err(e) => {
                    warn!(cause = %e, "failed to accept");
                    continue;
                }
            };

            let handler = handler.clone();

            tokio::spawn(async move {
                let (reader, writer) = tcp_stream.into_split();
                let connection = HttpConnection::new(reader, writer);
                match connection.process(handler).await {
                    Ok(_) => {
                        info!("finished process, connection shutdown");
                    }
                    Err(e) => {
                        error!("service has error, cause {}, connection shutdown", e);
                    }
                }
            });
        }
    }
}

impl Handler for Server {
    type RespBody = ResponseBody;
    type Error = Box<dyn Error + Send + Sync>;
    type Fut<'fut> = Pin<Box<dyn Future<Output = Result<Response<Self::RespBody>, Self::Error>> + Send + 'fut>>;

    fn call(&self, req: Request<ReqBody>) -> Self::Fut<'_> {
        Box::pin(async {
            let (parts, body) = req.into_parts();
            let header = RequestHeader::from(parts);
            let req_body = OptionReqBody::from(body);

            let path = header.uri().path();
            let route_result = self.router.at(path);

            let mut request_context = RequestContext::new(&header, route_result.params());

            let handler = route_result
                .router_items()
                .iter()
                .filter(|item| item.filter().matches(&request_context))
                .map(|item| item.handler())
                .take(1)
                .next()
                .unwrap_or(self.default_handler.as_ref());

            let response = handler.invoke(&mut request_context, req_body).await;
            Ok(response) 
            
        })
    }
}
