Documentation
use super::{MatchRoute, MatchRouter, Route};
use crate::{Router, HTTPMethod};

fn route_summary_get(router: &Router) -> Vec<Route> {
    let mut route_list;
    if let Some(root_path) = &router.root {
        route_list = vec![];
        for route in router.get.iter() {
            route_list.push((HTTPMethod::GET, format!("{}{}", root_path, route.1), route.2))
        }
    } else {
        route_list = router.get.clone();
    }
    
    for router in router.router.iter() {
        route_list.append(&mut route_summary_get(router));
    }
    route_list
}

fn route_summary_post(router: &Router) -> Vec<Route> {
    let mut route_list;
    if let Some(root_path) = &router.root {
        route_list = vec![];
        for route in router.post.iter() {
            route_list.push((HTTPMethod::POST, format!("{}{}", root_path, route.1), route.2))
        }
    } else {
        route_list = router.post.clone();
    }

    for router in router.router.iter() {
        route_list.append(&mut route_summary_post(router));
    }
    route_list
}

pub fn conversion_router(router: Router) -> MatchRouter {
    MatchRouter {
        get: conversion_route_list(&route_summary_get(&router)),
        post: conversion_route_list(&route_summary_post(&router)),
    }
}

fn conversion_route_list(route_list: &Vec<Route>) -> Vec<MatchRoute> {
    if route_list.is_empty() {
        return vec![];
    }

    let mut not_params_list = Vec::<MatchRoute>::new();
    let mut params_list = Vec::<MatchRoute>::new();

    for route in route_list {
        let match_route = conversion_route(route);
        if match_route.1.is_empty() {
            not_params_list.push(match_route);
        } else {
            params_list.push(match_route);
        }
    }

    not_params_list.sort_by(|a, b| b.0.cmp(&a.0));
    params_list.sort_by(|a, b| b.0.cmp(&a.0));
    not_params_list.append(&mut params_list);
    not_params_list
}

fn conversion_route(route: &Route) -> MatchRoute {
    let path_split_list: Vec<&str> = route.1.split("/:").collect();
    if path_split_list.len() == 1 {
        (format!(r"^{}$", path_split_list[0]), vec![], route.2)
    } else {
        let mut path_re = String::from("");
        let mut path_params: Vec<String> = vec![];
        for (index, path) in path_split_list.iter().enumerate() {
            if index == 0 {
                path_re.push_str(path);
            } else if let Some(index) = path.find('/') {
                path_params.push(path[..index].to_string());
                path_re.push_str(format!("{}{}", r"/([^/]*?)", &path[index..]).as_str());
            } else {
                if path.ends_with("+") {
                    path_params.push(path[..path.len() - 1].to_string());
                    path_re.push_str(r"/(.+)");
                    break;
                } else {
                    path_params.push(path.to_string());
                    path_re.push_str(r"/([^/]*?)");
                }
            }
        }
        (format!(r"^{}$", path_re), path_params, route.2)
    }
}

#[test]
fn test_conversion_route_the_path() {
    use crate::{request::HTTPMethod, Request, Response};

    fn handle_index(_request: &Request) -> crate::Result<Response> {
        Ok(Response::html_str("Hello Juri"))
    }

    let match_route = conversion_route(&(HTTPMethod::GET, "/aa".to_string(), handle_index));
    assert_eq!(match_route.0, "^/aa$");

    let match_route = conversion_route(&(HTTPMethod::GET, "/aa/:bb".to_string(), handle_index));
    assert_eq!(match_route.0, "^/aa/([^/]*?)$");

    let match_route = conversion_route(&(HTTPMethod::GET, "/aa/:bb/cc".to_string(), handle_index));
    assert_eq!(match_route.0, "^/aa/([^/]*?)/cc$");

    let match_route = conversion_route(&(HTTPMethod::GET, "/aa/:bb+".to_string(), handle_index));
    assert_eq!(match_route.0, "^/aa/(.+)$");
}