use crate::{
    handling::{
        methods::Method,
        request::{MediaType, Request},
        response::{Outcome, Response, Status},
    },
    utils::{mime::Mime, url_utils::RawUri},
};

/// A RouteBuilder struct
pub struct RoutBuilder {
    /// An optional name of the route
    name: Option<&'static str>,
    /// The [Method] via which the route is accesable
    method: Method,
    /// The path of the route, allows special cases:
    /// # Examples
    /// ```
    /// "/home"; // Only /home
    /// "/<home>/something";
    /// // Variable content the users provides this acts for /<anything>/something
    /// "/<home..>";
    /// // All Information after this sequence is irrelvent
    /// // Matches: /a, /a/b/c ...
    /// ```
    path: &'static str,
    /// The Handler function for this route, which gets called when the request need the route.
    /// Inputs to the function are an [Request] and the [Data] which represents the body of the
    /// [Request]. The Outcome is expected to be an [Outcome], which is a [Response], A [Status] if
    /// something went wrong and a [Status] page is need or a [Outcome::Forward] of the requests
    /// [Data] for the next [Route] to take care of.
    handler: fn(Request, Data) -> Outcome<Response, Status, Data>,
    /// The Specific answer format of the [Route] as a [MediaType]. Optional
    format: Option<MediaType>,
    /// The Optional Rank of the Route, dependent on its specificness. so the rank of a uri `"/home"` would be
    /// ranked high, whereas a uri of `"/<anything..>"` would be ranked the lowest
    /// If not given generated based on parematers.
    rank: Option<isize>,
}

/// A struct to define Routes on the Server
#[derive(Clone)]
pub struct Route {
    /// An optional name of the route
    pub name: Option<&'static str>,
    /// The [Method] via which the route is accesable
    pub method: Method,
    /// The Uri of the route, allows special cases:
    /// # Examples
    /// ```
    /// "/home"; // Only /home
    /// "/<home>/something";
    /// // Variable content the users provides this acts for /<anything>/something
    /// "/<home..>";
    /// // All Information after this sequence is irrelvent
    /// // Matches: /a, /a/b/c ...
    /// ```
    pub uri: RawUri,
    /// The Handler function for this route, which gets called when the request need the route.
    /// Inputs to the function are an [Request] and the [Data] which represents the body of the
    /// [Request]. The Outcome is expected to be an [Outcome], which is a [Response], A [Status] if
    /// something went wrong and a [Status] page is need or a [Outcome::Forward] of the requests
    /// [Data] for the next [Route] to take care of.
    pub handler: fn(Request, Data) -> Outcome<Response, Status, Data>,
    /// The Rank of the Route, dependent on its specificness. so the rank of a uri `"/home"` would be
    /// ranked high, whereas a uri of `"/<anything..>"` would be ranked the lowest
    pub rank: isize,
    /// The Specific answer format of the [Route] as a [MediaType]. Optional
    pub format: Option<MediaType>,
}

impl Route {
    /// generates a Route from a Routebuilder
    //TODO: ranking
    pub fn from(routeinfo: RoutBuilder) -> Self {
        let rank = routeinfo.rank.unwrap_or(0);
        Route {
            name: routeinfo.name,
            method: routeinfo.method,
            uri: routeinfo
                .path
                .try_into()
                .unwrap_or_else(|_| panic!("Incorrect RawUri for path {}", routeinfo.path)),
            handler: routeinfo.handler,
            rank,
            format: routeinfo.format,
        }
    }
}

/// Alias for using a &'a str for Uri

#[derive(Debug, Clone)]
/// A basic Body type for respones
pub struct Body {
    /// The Response body
    body: Vec<u8>,
    /// The Mime Type
    mime_type: Mime,
}

impl Body {
    /// New body of a Response
    pub fn new(body: Vec<u8>, mime_type: Mime) -> Self {
        Self { body, mime_type }
    }
    /// Sets the `mime_type` of the Body
    pub fn set_mime_type(&mut self, mime_type: Mime) {
        self.mime_type = mime_type;
    }
    /// Reassigns the body
    pub fn set_body(&mut self, body: Vec<u8>) {
        self.body = body;
    }
    /// mime_type of the body
    pub fn mime_type(&self) -> Mime {
        self.mime_type
    }
    /// cloned body as [`Vec<u8>`]
    pub fn body(&self) -> Vec<u8> {
        self.body.clone()
    }
}

#[derive(Debug, Clone)]
/// Data of the Body of a [Request]
pub struct Data {
    /// The Data
    pub buffer: Vec<u8>,
    /// For Split Data if it is complete
    pub is_complete: bool,
}

impl Data {
    /// Checks if the buffer.oen() is -0
    pub fn is_empty(&self) -> bool {
        self.buffer.len() == 0
    }
}